From dacd8c99ee08175b885489ca12322d275e4c3d11 Mon Sep 17 00:00:00 2001 From: Lech <88630083+Artemka374@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:03:00 +0200 Subject: [PATCH 001/106] feat: Add more buckets to call tracer (#1137) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- core/lib/multivm/src/tracers/call_tracer/metrics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/multivm/src/tracers/call_tracer/metrics.rs b/core/lib/multivm/src/tracers/call_tracer/metrics.rs index 5ee87bf02ce6..872f96864536 100644 --- a/core/lib/multivm/src/tracers/call_tracer/metrics.rs +++ b/core/lib/multivm/src/tracers/call_tracer/metrics.rs @@ -4,10 +4,10 @@ use vise::{Buckets, Histogram, Metrics}; #[metrics(prefix = "vm_call_tracer")] pub struct CallMetrics { /// Maximum call stack depth during the execution of the transaction. - #[metrics(buckets = Buckets::exponential(1.0..=1024.0, 2.0))] + #[metrics(buckets = Buckets::exponential(1.0..=4096.0, 2.0))] pub call_stack_depth: Histogram, /// Maximum number of near calls during the execution of the transaction. - #[metrics(buckets = Buckets::exponential(1.0..=1024.0, 2.0))] + #[metrics(buckets = Buckets::exponential(1.0..=4096.0, 2.0))] pub max_near_calls: Histogram, } From 00d342932c6305055f719afaecf6a0eeeb3ca63a Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Tue, 20 Feb 2024 15:26:37 +0400 Subject: [PATCH 002/106] feat(vlog): Remove env getters from vlog (#1077) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - Removes `*_from_env` functions from `vlog` crate. - Introduces `ObservabilityConfig` for core and EN with env variable based constructors that match the old behavior. - Changes the binaries to use new approach. ## Why ❔ - `vlog` is a generic library, so it should have no assumptions on the configuration system. It should be for users of `vlog` to decide where they get the configuration from. --- core/bin/block_reverter/src/main.rs | 21 +++-- core/bin/contract-verifier/src/main.rs | 24 ++--- core/bin/external_node/src/config/mod.rs | 1 + .../external_node/src/config/observability.rs | 39 ++++++++ core/bin/external_node/src/main.rs | 22 ++--- .../src/main.rs | 19 ++-- core/bin/snapshots_creator/src/main.rs | 23 ++--- core/bin/zksync_server/src/main.rs | 22 ++--- core/lib/config/src/configs/mod.rs | 2 + core/lib/config/src/configs/observability.rs | 12 +++ core/lib/env_config/src/lib.rs | 1 + core/lib/env_config/src/observability.rs | 43 +++++++++ core/lib/protobuf_config/src/lib.rs | 1 + core/lib/protobuf_config/src/observability.rs | 24 +++++ .../src/proto/observability.proto | 9 ++ core/lib/vlog/src/lib.rs | 89 +++++-------------- .../node/node_framework/examples/main_node.rs | 14 ++- core/tests/loadnext/src/main.rs | 26 ++++-- prover/proof_fri_compressor/src/main.rs | 22 ++--- prover/prover_fri/src/main.rs | 22 ++--- prover/prover_fri_gateway/src/main.rs | 22 ++--- prover/witness_generator/src/main.rs | 22 ++--- prover/witness_vector_generator/src/main.rs | 22 ++--- 23 files changed, 312 insertions(+), 190 deletions(-) create mode 100644 core/bin/external_node/src/config/observability.rs create mode 100644 core/lib/config/src/configs/observability.rs create mode 100644 core/lib/env_config/src/observability.rs create mode 100644 core/lib/protobuf_config/src/observability.rs create mode 100644 core/lib/protobuf_config/src/proto/observability.proto diff --git a/core/bin/block_reverter/src/main.rs b/core/bin/block_reverter/src/main.rs index f7cbc20f554d..d26f9e0ec3b0 100644 --- a/core/bin/block_reverter/src/main.rs +++ b/core/bin/block_reverter/src/main.rs @@ -1,7 +1,10 @@ use anyhow::Context as _; use clap::{Parser, Subcommand}; use tokio::io::{self, AsyncReadExt}; -use zksync_config::{ContractsConfig, DBConfig, ETHClientConfig, ETHSenderConfig, PostgresConfig}; +use zksync_config::{ + configs::ObservabilityConfig, ContractsConfig, DBConfig, ETHClientConfig, ETHSenderConfig, + PostgresConfig, +}; use zksync_core::block_reverter::{ BlockReverter, BlockReverterEthConfig, BlockReverterFlags, L1ExecutedBatchesRevert, }; @@ -68,19 +71,19 @@ enum Command { #[tokio::main] async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { builder = builder .with_sentry_url(&sentry_url) .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); diff --git a/core/bin/contract-verifier/src/main.rs b/core/bin/contract-verifier/src/main.rs index 477b4dc0722d..9030236cb52d 100644 --- a/core/bin/contract-verifier/src/main.rs +++ b/core/bin/contract-verifier/src/main.rs @@ -4,7 +4,10 @@ use anyhow::Context as _; use futures::{channel::mpsc, executor::block_on, SinkExt, StreamExt}; use prometheus_exporter::PrometheusExporterConfig; use tokio::sync::watch; -use zksync_config::{configs::PrometheusConfig, ApiConfig, ContractVerifierConfig, PostgresConfig}; +use zksync_config::{ + configs::{ObservabilityConfig, PrometheusConfig}, + ApiConfig, ContractVerifierConfig, PostgresConfig, +}; use zksync_dal::ConnectionPool; use zksync_env_config::FromEnv; use zksync_queued_job_processor::JobProcessor; @@ -140,24 +143,23 @@ async fn main() -> anyhow::Result<()> { .await .unwrap(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); - + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = &sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder .with_sentry_url(sentry_url) .expect("Invalid Sentry URL") - .with_sentry_environment(environment); + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); // Report whether sentry is running after the logging subsystem was initialized. - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { tracing::info!("Sentry configured with URL: {sentry_url}"); } else { tracing::info!("No sentry URL was provided"); diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index e37a71d79c6f..e5e61d3f6c10 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -20,6 +20,7 @@ use zksync_web3_decl::{ namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; +pub(crate) mod observability; #[cfg(test)] mod tests; diff --git a/core/bin/external_node/src/config/observability.rs b/core/bin/external_node/src/config/observability.rs new file mode 100644 index 000000000000..ddc2256e78bc --- /dev/null +++ b/core/bin/external_node/src/config/observability.rs @@ -0,0 +1,39 @@ +use zksync_config::configs::ObservabilityConfig; + +pub fn observability_config_from_env() -> anyhow::Result { + // The logic in this method mimics the historical logic of loading observability options + // This is left intact, since some of the existing deployments may rely on the this behavior. + let sentry_url = if let Ok(sentry_url) = std::env::var("MISC_SENTRY_URL") { + if sentry_url == "unset" { + None + } else { + Some(sentry_url) + } + } else { + None + }; + let sentry_environment = std::env::var("EN_SENTRY_ENVIRONMENT").ok().or_else(|| { + let l1_network = std::env::var("CHAIN_ETH_NETWORK").ok(); + let l2_network = std::env::var("CHAIN_ETH_ZKSYNC_NETWORK").ok(); + match (l1_network, l2_network) { + (Some(l1_network), Some(l2_network)) => { + Some(format!("{} - {}", l1_network, l2_network)) + } + _ => None, + } + }); + let log_format = if let Ok(log_format) = std::env::var("MISC_LOG_FORMAT") { + if log_format != "plain" && log_format != "json" { + anyhow::bail!("MISC_LOG_FORMAT has an unexpected value {}", log_format); + } + log_format + } else { + "plain".to_string() + }; + + Ok(ObservabilityConfig { + sentry_url, + sentry_environment, + log_format, + }) +} diff --git a/core/bin/external_node/src/main.rs b/core/bin/external_node/src/main.rs index 749d85d6e53c..8211e8596ab2 100644 --- a/core/bin/external_node/src/main.rs +++ b/core/bin/external_node/src/main.rs @@ -40,7 +40,9 @@ use zksync_storage::RocksDB; use zksync_utils::wait_for_tasks::wait_for_tasks; use crate::{ - config::ExternalNodeConfig, helpers::MainNodeHealthCheck, init::ensure_storage_initialized, + config::{observability::observability_config_from_env, ExternalNodeConfig}, + helpers::MainNodeHealthCheck, + init::ensure_storage_initialized, }; mod config; @@ -423,24 +425,24 @@ async fn main() -> anyhow::Result<()> { // Initial setup. let opt = Cli::parse(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + observability_config_from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = &sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder .with_sentry_url(sentry_url) .expect("Invalid Sentry URL") - .with_sentry_environment(environment); + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); // Report whether sentry is running after the logging subsystem was initialized. - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { tracing::info!("Sentry configured with URL: {sentry_url}"); } else { tracing::info!("No sentry URL was provided"); diff --git a/core/bin/merkle_tree_consistency_checker/src/main.rs b/core/bin/merkle_tree_consistency_checker/src/main.rs index 6d64729f9b6f..1f3dc6df69c5 100644 --- a/core/bin/merkle_tree_consistency_checker/src/main.rs +++ b/core/bin/merkle_tree_consistency_checker/src/main.rs @@ -2,7 +2,7 @@ use std::{path::Path, time::Instant}; use anyhow::Context as _; use clap::Parser; -use zksync_config::DBConfig; +use zksync_config::{configs::ObservabilityConfig, DBConfig}; use zksync_env_config::FromEnv; use zksync_merkle_tree::domain::ZkSyncTree; use zksync_storage::RocksDB; @@ -48,19 +48,18 @@ impl Cli { } fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); - + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { builder = builder .with_sentry_url(&sentry_url) .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); diff --git a/core/bin/snapshots_creator/src/main.rs b/core/bin/snapshots_creator/src/main.rs index c9a52fe0d746..8d6ff39a93d1 100644 --- a/core/bin/snapshots_creator/src/main.rs +++ b/core/bin/snapshots_creator/src/main.rs @@ -12,7 +12,10 @@ use anyhow::Context as _; use prometheus_exporter::PrometheusExporterConfig; use tokio::{sync::watch, task::JoinHandle}; -use zksync_config::{configs::PrometheusConfig, PostgresConfig, SnapshotsCreatorConfig}; +use zksync_config::{ + configs::{ObservabilityConfig, PrometheusConfig}, + PostgresConfig, SnapshotsCreatorConfig, +}; use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::SnapshotsObjectStoreConfig, FromEnv}; use zksync_object_store::ObjectStoreFactory; @@ -50,23 +53,23 @@ const MIN_CHUNK_COUNT: u64 = 10; async fn main() -> anyhow::Result<()> { let (stop_sender, stop_receiver) = watch::channel(false); - tracing::info!("Starting snapshots creator"); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let prometheus_exporter_task = maybe_enable_prometheus_metrics(stop_receiver).await?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { builder = builder .with_sentry_url(&sentry_url) .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); + tracing::info!("Starting snapshots creator"); let object_store_config = SnapshotsObjectStoreConfig::from_env().context("SnapshotsObjectStoreConfig::from_env()")?; diff --git a/core/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs index b17913d30947..a72acdad81d5 100644 --- a/core/bin/zksync_server/src/main.rs +++ b/core/bin/zksync_server/src/main.rs @@ -11,8 +11,8 @@ use zksync_config::{ }, fri_prover_group::FriProverGroupConfig, house_keeper::HouseKeeperConfig, - FriProofCompressorConfig, FriProverConfig, FriWitnessGeneratorConfig, PrometheusConfig, - ProofDataHandlerConfig, WitnessGeneratorConfig, + FriProofCompressorConfig, FriProverConfig, FriWitnessGeneratorConfig, ObservabilityConfig, + PrometheusConfig, ProofDataHandlerConfig, WitnessGeneratorConfig, }, ApiConfig, ContractsConfig, DBConfig, ETHClientConfig, ETHSenderConfig, ETHWatchConfig, GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, @@ -68,24 +68,24 @@ impl FromStr for ComponentsToRun { async fn main() -> anyhow::Result<()> { let opt = Cli::parse(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = &sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder .with_sentry_url(sentry_url) .expect("Invalid Sentry URL") - .with_sentry_environment(environment); + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); // Report whether sentry is running after the logging subsystem was initialized. - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { tracing::info!("Sentry configured with URL: {sentry_url}"); } else { tracing::info!("No sentry URL was provided"); diff --git a/core/lib/config/src/configs/mod.rs b/core/lib/config/src/configs/mod.rs index fc0e7eb6d4d2..f9ad80dbe344 100644 --- a/core/lib/config/src/configs/mod.rs +++ b/core/lib/config/src/configs/mod.rs @@ -14,6 +14,7 @@ pub use self::{ fri_witness_generator::FriWitnessGeneratorConfig, fri_witness_vector_generator::FriWitnessVectorGeneratorConfig, object_store::ObjectStoreConfig, + observability::ObservabilityConfig, proof_data_handler::ProofDataHandlerConfig, snapshots_creator::SnapshotsCreatorConfig, utils::PrometheusConfig, @@ -37,6 +38,7 @@ pub mod fri_witness_generator; pub mod fri_witness_vector_generator; pub mod house_keeper; pub mod object_store; +pub mod observability; pub mod proof_data_handler; pub mod snapshots_creator; pub mod utils; diff --git a/core/lib/config/src/configs/observability.rs b/core/lib/config/src/configs/observability.rs new file mode 100644 index 000000000000..ae9fb64120f5 --- /dev/null +++ b/core/lib/config/src/configs/observability.rs @@ -0,0 +1,12 @@ +/// Configuration for the essential observability stack, like +/// logging and sentry integration. +#[derive(Debug, Clone)] +pub struct ObservabilityConfig { + /// URL of the Sentry instance to send events to. + pub sentry_url: Option, + /// Name of the environment to use in Sentry. + pub sentry_environment: Option, + /// Format of the logs as expected by the `vlog` crate. + /// Currently must be either `plain` or `json`. + pub log_format: String, +} diff --git a/core/lib/env_config/src/lib.rs b/core/lib/env_config/src/lib.rs index 5186b6e41982..973e2ff9ae5a 100644 --- a/core/lib/env_config/src/lib.rs +++ b/core/lib/env_config/src/lib.rs @@ -18,6 +18,7 @@ mod fri_witness_generator; mod fri_witness_vector_generator; mod house_keeper; pub mod object_store; +mod observability; mod proof_data_handler; mod snapshots_creator; mod utils; diff --git a/core/lib/env_config/src/observability.rs b/core/lib/env_config/src/observability.rs new file mode 100644 index 000000000000..a168c664b227 --- /dev/null +++ b/core/lib/env_config/src/observability.rs @@ -0,0 +1,43 @@ +use zksync_config::configs::ObservabilityConfig; + +use crate::FromEnv; + +impl FromEnv for ObservabilityConfig { + fn from_env() -> anyhow::Result { + // The logic in this method mimics the historical logic of loading observability options + // This is left intact, since some of the existing deployments may rely on the this behavior. + let sentry_url = if let Ok(sentry_url) = std::env::var("MISC_SENTRY_URL") { + if sentry_url == "unset" { + None + } else { + Some(sentry_url) + } + } else { + None + }; + let sentry_environment = { + let l1_network = std::env::var("CHAIN_ETH_NETWORK").ok(); + let l2_network = std::env::var("CHAIN_ETH_ZKSYNC_NETWORK").ok(); + match (l1_network, l2_network) { + (Some(l1_network), Some(l2_network)) => { + Some(format!("{} - {}", l1_network, l2_network)) + } + _ => None, + } + }; + let log_format = if let Ok(log_format) = std::env::var("MISC_LOG_FORMAT") { + if log_format != "plain" && log_format != "json" { + anyhow::bail!("MISC_LOG_FORMAT has an unexpected value {}", log_format); + } + log_format + } else { + "plain".to_string() + }; + + Ok(ObservabilityConfig { + sentry_url, + sentry_environment, + log_format, + }) + } +} diff --git a/core/lib/protobuf_config/src/lib.rs b/core/lib/protobuf_config/src/lib.rs index 164fbfa7c55f..b0814b364a19 100644 --- a/core/lib/protobuf_config/src/lib.rs +++ b/core/lib/protobuf_config/src/lib.rs @@ -21,6 +21,7 @@ mod fri_witness_generator; mod fri_witness_vector_generator; mod house_keeper; mod object_store; +mod observability; mod proof_data_handler; mod snapshots_creator; mod witness_generator; diff --git a/core/lib/protobuf_config/src/observability.rs b/core/lib/protobuf_config/src/observability.rs new file mode 100644 index 000000000000..1549a0bf38b5 --- /dev/null +++ b/core/lib/protobuf_config/src/observability.rs @@ -0,0 +1,24 @@ +use anyhow::Context as _; +use zksync_config::configs; +use zksync_protobuf::required; + +use crate::{proto, repr::ProtoRepr}; + +impl ProtoRepr for proto::Observability { + type Type = configs::ObservabilityConfig; + fn read(&self) -> anyhow::Result { + Ok(Self::Type { + sentry_url: self.sentry_url.clone(), + sentry_environment: self.sentry_environment.clone(), + log_format: required(&self.log_format).context("log_format")?.clone(), + }) + } + + fn build(this: &Self::Type) -> Self { + Self { + sentry_url: this.sentry_url.clone(), + sentry_environment: this.sentry_environment.clone(), + log_format: Some(this.log_format.clone()), + } + } +} diff --git a/core/lib/protobuf_config/src/proto/observability.proto b/core/lib/protobuf_config/src/proto/observability.proto new file mode 100644 index 000000000000..e03948e68135 --- /dev/null +++ b/core/lib/protobuf_config/src/proto/observability.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package zksync.config; + +message Observability { + optional string sentry_url = 1; // optional + optional string sentry_environment = 2; // optional + optional string log_format = 3; // required +} diff --git a/core/lib/vlog/src/lib.rs b/core/lib/vlog/src/lib.rs index 1ea573148c4a..c8e4761744eb 100644 --- a/core/lib/vlog/src/lib.rs +++ b/core/lib/vlog/src/lib.rs @@ -1,7 +1,7 @@ //! This module contains the observability subsystem. //! It is responsible for providing a centralized interface for consistent observability configuration. -use std::{backtrace::Backtrace, borrow::Cow, panic::PanicInfo}; +use std::{backtrace::Backtrace, borrow::Cow, panic::PanicInfo, str::FromStr}; // Temporary re-export of `sentry::capture_message` aiming to simplify the transition from `vlog` to using // crates directly. @@ -17,6 +17,29 @@ pub enum LogFormat { Json, } +#[derive(Debug)] +pub struct LogFormatError(&'static str); + +impl std::fmt::Display for LogFormatError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl std::error::Error for LogFormatError {} + +impl FromStr for LogFormat { + type Err = LogFormatError; + + fn from_str(s: &str) -> Result { + match s { + "plain" => Ok(LogFormat::Plain), + "json" => Ok(LogFormat::Json), + _ => Err(LogFormatError("invalid log format")), + } + } +} + /// Builder for the observability subsystem. /// Currently capable of configuring logging output and sentry integration. #[derive(Debug, Default)] @@ -125,70 +148,6 @@ impl ObservabilityBuilder { } } -/// Loads the log format from the environment variable according to the existing zkSync configuration scheme. -/// If the variable is not set, the default value is used. -/// -/// This is a deprecated function existing for compatibility with the old configuration scheme. -/// Not recommended for use in new applications. -/// -/// # Panics -/// -/// Panics if the value of the variable is set, but is not `plain` or `json`. -#[deprecated( - note = "This function will be removed in the future. Applications are expected to handle their configuration themselves." -)] -pub fn log_format_from_env() -> LogFormat { - match std::env::var("MISC_LOG_FORMAT") { - Ok(log_format) => match log_format.as_str() { - "plain" => LogFormat::Plain, - "json" => LogFormat::Json, - _ => panic!("MISC_LOG_FORMAT has an unexpected value {}", log_format), - }, - Err(_) => LogFormat::Plain, - } -} - -/// Loads the Sentry URL from the environment variable according to the existing zkSync configuration scheme. -/// If the environment value is present but the value is `unset`, `None` will be returned for compatibility with the -/// existing configuration setup. -/// -/// This is a deprecated function existing for compatibility with the old configuration scheme. -/// Not recommended for use in new applications. -#[deprecated( - note = "This function will be removed in the future. Applications are expected to handle their configuration themselves." -)] -pub fn sentry_url_from_env() -> Option { - match std::env::var("MISC_SENTRY_URL") { - Ok(str) if str == "unset" => { - // This bogus value may be provided an sentry is expected to just not be initialized in this case. - None - } - Ok(str) => Some(str), - Err(_) => None, - } -} - -/// Prepared the Sentry environment ID from the environment variable according to the existing zkSync configuration -/// scheme. -/// This function mimics like `vlog` configuration worked historically, e.g. it would also try to load environment -/// for the external node, and the EN variable is preferred if it is set. -/// -/// This is a deprecated function existing for compatibility with the old configuration scheme. -/// Not recommended for use in new applications. -#[deprecated( - note = "This function will be removed in the future. Applications are expected to handle their configuration themselves." -)] -pub fn environment_from_env() -> Option { - if let Ok(en_env) = std::env::var("EN_SENTRY_ENVIRONMENT") { - return Some(en_env); - } - - let l1_network = std::env::var("CHAIN_ETH_NETWORK").ok()?; - let l2_network = std::env::var("CHAIN_ETH_ZKSYNC_NETWORK").ok()?; - - Some(format!("{} - {}", l1_network, l2_network)) -} - fn json_panic_handler(panic_info: &PanicInfo) { let backtrace = Backtrace::capture(); let timestamp = chrono::Utc::now(); diff --git a/core/node/node_framework/examples/main_node.rs b/core/node/node_framework/examples/main_node.rs index 680bbbe5fdaa..a6fa6a9e042e 100644 --- a/core/node/node_framework/examples/main_node.rs +++ b/core/node/node_framework/examples/main_node.rs @@ -2,8 +2,12 @@ //! This example defines a `ResourceProvider` that works using the main node env config, and //! initializes a single task with a health check server. +use anyhow::Context; use zksync_config::{ - configs::chain::{MempoolConfig, NetworkConfig, OperationsManagerConfig, StateKeeperConfig}, + configs::{ + chain::{MempoolConfig, NetworkConfig, OperationsManagerConfig, StateKeeperConfig}, + ObservabilityConfig, + }, ApiConfig, ContractsConfig, DBConfig, ETHClientConfig, GasAdjusterConfig, ObjectStoreConfig, PostgresConfig, }; @@ -110,8 +114,12 @@ impl MainNodeBuilder { } fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let _guard = vlog::ObservabilityBuilder::new() .with_log_format(log_format) .build(); diff --git a/core/tests/loadnext/src/main.rs b/core/tests/loadnext/src/main.rs index 595532706c74..6a3125931f12 100644 --- a/core/tests/loadnext/src/main.rs +++ b/core/tests/loadnext/src/main.rs @@ -18,12 +18,26 @@ use zksync_config::configs::api::PrometheusConfig; #[tokio::main] async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + // We don't want to introduce dependency on `zksync_env_config` in loadnext, + // but we historically rely on the environment variables for the observability configuration, + // so we load them directly here. + let log_format: vlog::LogFormat = std::env::var("MISC_LOG_FORMAT") + .ok() + .unwrap_or("plain".to_string()) + .parse()?; + let sentry_url = std::env::var("MISC_SENTRY_URL") + .ok() + .filter(|s| s != "unset"); + let environment = { + let l1_network = std::env::var("CHAIN_ETH_NETWORK").ok(); + let l2_network = std::env::var("CHAIN_ETH_ZKSYNC_NETWORK").ok(); + match (l1_network, l2_network) { + (Some(l1_network), Some(l2_network)) => { + Some(format!("{} - {}", l1_network, l2_network)) + } + _ => None, + } + }; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); if let Some(sentry_url) = sentry_url { diff --git a/prover/proof_fri_compressor/src/main.rs b/prover/proof_fri_compressor/src/main.rs index 33aaf3b9162b..e148a3687669 100644 --- a/prover/proof_fri_compressor/src/main.rs +++ b/prover/proof_fri_compressor/src/main.rs @@ -4,7 +4,7 @@ use anyhow::Context as _; use prometheus_exporter::PrometheusExporterConfig; use structopt::StructOpt; use tokio::sync::{oneshot, watch}; -use zksync_config::configs::{FriProofCompressorConfig, PostgresConfig}; +use zksync_config::configs::{FriProofCompressorConfig, ObservabilityConfig, PostgresConfig}; use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::ProverObjectStoreConfig, FromEnv}; use zksync_object_store::ObjectStoreFactory; @@ -32,19 +32,19 @@ struct Opt { #[tokio::main] async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder - .with_sentry_url(&sentry_url) - .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .with_sentry_url(sentry_url) + .expect("Invalid Sentry URL") + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); diff --git a/prover/prover_fri/src/main.rs b/prover/prover_fri/src/main.rs index e8c298c0663d..53e22b7563e3 100644 --- a/prover/prover_fri/src/main.rs +++ b/prover/prover_fri/src/main.rs @@ -9,7 +9,7 @@ use tokio::{ task::JoinHandle, }; use zksync_config::configs::{ - fri_prover_group::FriProverGroupConfig, FriProverConfig, PostgresConfig, + fri_prover_group::FriProverGroupConfig, FriProverConfig, ObservabilityConfig, PostgresConfig, }; use zksync_dal::{ fri_prover_dal::types::{GpuProverInstanceStatus, SocketAddress}, @@ -55,24 +55,24 @@ async fn graceful_shutdown(port: u16) -> anyhow::Result #[tokio::main] async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = &sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder .with_sentry_url(sentry_url) - .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .expect("Invalid Sentry URL") + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); // Report whether sentry is running after the logging subsystem was initialized. - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { tracing::info!("Sentry configured with URL: {sentry_url}",); } else { tracing::info!("No sentry URL was provided"); diff --git a/prover/prover_fri_gateway/src/main.rs b/prover/prover_fri_gateway/src/main.rs index 0ab2475d4196..9c73a8be6f1d 100644 --- a/prover/prover_fri_gateway/src/main.rs +++ b/prover/prover_fri_gateway/src/main.rs @@ -2,7 +2,7 @@ use anyhow::Context as _; use prometheus_exporter::PrometheusExporterConfig; use reqwest::Client; use tokio::sync::{oneshot, watch}; -use zksync_config::configs::{FriProverGatewayConfig, PostgresConfig}; +use zksync_config::configs::{FriProverGatewayConfig, ObservabilityConfig, PostgresConfig}; use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::ProverObjectStoreConfig, FromEnv}; use zksync_object_store::ObjectStoreFactory; @@ -18,19 +18,19 @@ mod proof_submitter; #[tokio::main] async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder - .with_sentry_url(&sentry_url) - .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .with_sentry_url(sentry_url) + .expect("Invalid Sentry URL") + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); diff --git a/prover/witness_generator/src/main.rs b/prover/witness_generator/src/main.rs index 8a19e4d450a8..8d89f8df862b 100644 --- a/prover/witness_generator/src/main.rs +++ b/prover/witness_generator/src/main.rs @@ -8,7 +8,7 @@ use prometheus_exporter::PrometheusExporterConfig; use structopt::StructOpt; use tokio::sync::watch; use zksync_config::{ - configs::{FriWitnessGeneratorConfig, PostgresConfig, PrometheusConfig}, + configs::{FriWitnessGeneratorConfig, ObservabilityConfig, PostgresConfig, PrometheusConfig}, ObjectStoreConfig, }; use zksync_dal::ConnectionPool; @@ -62,24 +62,24 @@ struct Opt { #[tokio::main] async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = &sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder .with_sentry_url(sentry_url) - .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .expect("Invalid Sentry URL") + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); // Report whether sentry is running after the logging subsystem was initialized. - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = observability_config.sentry_url { tracing::info!("Sentry configured with URL: {sentry_url}",); } else { tracing::info!("No sentry URL was provided"); diff --git a/prover/witness_vector_generator/src/main.rs b/prover/witness_vector_generator/src/main.rs index 773a71fe46c6..455f4b6210ff 100644 --- a/prover/witness_vector_generator/src/main.rs +++ b/prover/witness_vector_generator/src/main.rs @@ -6,7 +6,7 @@ use structopt::StructOpt; use tokio::sync::{oneshot, watch}; use zksync_config::configs::{ fri_prover_group::FriProverGroupConfig, FriProverConfig, FriWitnessVectorGeneratorConfig, - PostgresConfig, + ObservabilityConfig, PostgresConfig, }; use zksync_dal::ConnectionPool; use zksync_env_config::{object_store::ProverObjectStoreConfig, FromEnv}; @@ -34,19 +34,19 @@ struct Opt { #[tokio::main] async fn main() -> anyhow::Result<()> { - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let log_format = vlog::log_format_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let sentry_url = vlog::sentry_url_from_env(); - #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. - let environment = vlog::environment_from_env(); + let observability_config = + ObservabilityConfig::from_env().context("ObservabilityConfig::from_env()")?; + let log_format: vlog::LogFormat = observability_config + .log_format + .parse() + .context("Invalid log format")?; let mut builder = vlog::ObservabilityBuilder::new().with_log_format(log_format); - if let Some(sentry_url) = sentry_url { + if let Some(sentry_url) = &observability_config.sentry_url { builder = builder - .with_sentry_url(&sentry_url) - .context("Invalid Sentry URL")? - .with_sentry_environment(environment); + .with_sentry_url(sentry_url) + .expect("Invalid Sentry URL") + .with_sentry_environment(observability_config.sentry_environment); } let _guard = builder.build(); From b538d1a411f58a4106afea8f9a71a3ea2ad9352d Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Tue, 20 Feb 2024 13:42:40 +0200 Subject: [PATCH 003/106] feat(api): Create RPC method to return all tokens (#1103) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - Creates `en_syncTokens` RPC method that returns all tokens optionally filtered by the miniblock at which the token was deployed. - Uses this method during snapshot recovery to recover tokens. ## Why ❔ It's necessary to recover tokens in order for the VM sandbox to work properly. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [x] Tests for the changes have been added / updated. - [x] Documentation comments have been added / updated. - [x] Code has been formatted via `zk fmt` and `zk lint`. - [x] Spellcheck has been run via `zk spellcheck`. - [x] Linkcheck has been run via `zk linkcheck`. --- ...149cdcb6c7ee74047567785a38265a03720be.json | 16 -- ...cfb3ba0659b6fcc582e174ee80601b54f89d9.json | 35 +++ ...fadbcfc343374fad173df0cc8db38419a9726.json | 14 + ...4470914b52e2d714e9deb903d62a5d66f0e04.json | 44 +++ core/lib/dal/src/storage_logs_dal.rs | 189 +++++++++++++ core/lib/dal/src/tokens_dal.rs | 256 ++++++++++++++---- core/lib/dal/src/tokens_web3_dal.rs | 81 +++++- core/lib/snapshots_applier/src/lib.rs | 100 ++++++- core/lib/snapshots_applier/src/tests/mod.rs | 88 +++++- core/lib/snapshots_applier/src/tests/utils.rs | 73 +++-- core/lib/web3_decl/src/namespaces/en.rs | 9 +- .../web3/backend_jsonrpsee/namespaces/en.rs | 11 +- .../src/api_server/web3/namespaces/en.rs | 22 +- .../tests/snapshot-recovery.test.ts | 122 ++++++--- 14 files changed, 891 insertions(+), 169 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-35c78c8f04e2db43285bbe5f485149cdcb6c7ee74047567785a38265a03720be.json create mode 100644 core/lib/dal/.sqlx/query-55e6f5ea121090034c8920dffb7cfb3ba0659b6fcc582e174ee80601b54f89d9.json create mode 100644 core/lib/dal/.sqlx/query-6849be0788a509e4e68acc2da4bfadbcfc343374fad173df0cc8db38419a9726.json create mode 100644 core/lib/dal/.sqlx/query-a1f4334b6bc1642c1bc0ff4ffa34470914b52e2d714e9deb903d62a5d66f0e04.json diff --git a/core/lib/dal/.sqlx/query-35c78c8f04e2db43285bbe5f485149cdcb6c7ee74047567785a38265a03720be.json b/core/lib/dal/.sqlx/query-35c78c8f04e2db43285bbe5f485149cdcb6c7ee74047567785a38265a03720be.json deleted file mode 100644 index 2e8ef0ae4ec7..000000000000 --- a/core/lib/dal/.sqlx/query-35c78c8f04e2db43285bbe5f485149cdcb6c7ee74047567785a38265a03720be.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n DELETE FROM tokens\n WHERE\n l2_address IN (\n SELECT\n SUBSTRING(key, 12, 20)\n FROM\n storage_logs\n WHERE\n storage_logs.address = $1\n AND miniblock_number > $2\n AND NOT EXISTS (\n SELECT\n 1\n FROM\n storage_logs AS s\n WHERE\n s.hashed_key = storage_logs.hashed_key\n AND (s.miniblock_number, s.operation_number) >= (storage_logs.miniblock_number, storage_logs.operation_number)\n AND s.value = $3\n )\n )\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea", - "Int8", - "Bytea" - ] - }, - "nullable": [] - }, - "hash": "35c78c8f04e2db43285bbe5f485149cdcb6c7ee74047567785a38265a03720be" -} diff --git a/core/lib/dal/.sqlx/query-55e6f5ea121090034c8920dffb7cfb3ba0659b6fcc582e174ee80601b54f89d9.json b/core/lib/dal/.sqlx/query-55e6f5ea121090034c8920dffb7cfb3ba0659b6fcc582e174ee80601b54f89d9.json new file mode 100644 index 000000000000..117d1bad9bf2 --- /dev/null +++ b/core/lib/dal/.sqlx/query-55e6f5ea121090034c8920dffb7cfb3ba0659b6fcc582e174ee80601b54f89d9.json @@ -0,0 +1,35 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT DISTINCT\n ON (hashed_key) hashed_key,\n miniblock_number,\n value\n FROM\n storage_logs\n WHERE\n hashed_key = ANY ($1)\n AND miniblock_number <= $2\n ORDER BY\n hashed_key,\n miniblock_number DESC,\n operation_number DESC\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "hashed_key", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "miniblock_number", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "value", + "type_info": "Bytea" + } + ], + "parameters": { + "Left": [ + "ByteaArray", + "Int8" + ] + }, + "nullable": [ + false, + false, + false + ] + }, + "hash": "55e6f5ea121090034c8920dffb7cfb3ba0659b6fcc582e174ee80601b54f89d9" +} diff --git a/core/lib/dal/.sqlx/query-6849be0788a509e4e68acc2da4bfadbcfc343374fad173df0cc8db38419a9726.json b/core/lib/dal/.sqlx/query-6849be0788a509e4e68acc2da4bfadbcfc343374fad173df0cc8db38419a9726.json new file mode 100644 index 000000000000..72dbb2a4178b --- /dev/null +++ b/core/lib/dal/.sqlx/query-6849be0788a509e4e68acc2da4bfadbcfc343374fad173df0cc8db38419a9726.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM tokens\n WHERE\n l2_address = ANY ($1)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [] + }, + "hash": "6849be0788a509e4e68acc2da4bfadbcfc343374fad173df0cc8db38419a9726" +} diff --git a/core/lib/dal/.sqlx/query-a1f4334b6bc1642c1bc0ff4ffa34470914b52e2d714e9deb903d62a5d66f0e04.json b/core/lib/dal/.sqlx/query-a1f4334b6bc1642c1bc0ff4ffa34470914b52e2d714e9deb903d62a5d66f0e04.json new file mode 100644 index 000000000000..82612fb53277 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a1f4334b6bc1642c1bc0ff4ffa34470914b52e2d714e9deb903d62a5d66f0e04.json @@ -0,0 +1,44 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n l1_address,\n l2_address,\n NAME,\n symbol,\n decimals\n FROM\n tokens\n ORDER BY\n symbol\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "l1_address", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "l2_address", + "type_info": "Bytea" + }, + { + "ordinal": 2, + "name": "name", + "type_info": "Varchar" + }, + { + "ordinal": 3, + "name": "symbol", + "type_info": "Varchar" + }, + { + "ordinal": 4, + "name": "decimals", + "type_info": "Int4" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + false, + false, + false, + false, + false + ] + }, + "hash": "a1f4334b6bc1642c1bc0ff4ffa34470914b52e2d714e9deb903d62a5d66f0e04" +} diff --git a/core/lib/dal/src/storage_logs_dal.rs b/core/lib/dal/src/storage_logs_dal.rs index 12d958ed859c..51d6e168b3a0 100644 --- a/core/lib/dal/src/storage_logs_dal.rs +++ b/core/lib/dal/src/storage_logs_dal.rs @@ -300,6 +300,55 @@ impl StorageLogsDal<'_, '_> { row.count > 0 } + /// Returns addresses and the corresponding deployment miniblock numbers among the specified contract + /// `addresses`. `at_miniblock` allows filtering deployment by miniblocks. + pub async fn filter_deployed_contracts( + &mut self, + addresses: impl Iterator, + at_miniblock: Option, + ) -> sqlx::Result> { + let (bytecode_hashed_keys, address_by_hashed_key): (Vec<_>, HashMap<_, _>) = addresses + .map(|address| { + let hashed_key = get_code_key(&address).hashed_key().0; + (hashed_key, (hashed_key, address)) + }) + .unzip(); + let max_miniblock_number = at_miniblock.map_or(u32::MAX, |number| number.0); + // Get the latest `value` and corresponding `miniblock_number` for each of `bytecode_hashed_keys`. For failed deployments, + // this value will equal `FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH`, so that they can be easily filtered. + let rows = sqlx::query!( + r#" + SELECT DISTINCT + ON (hashed_key) hashed_key, + miniblock_number, + value + FROM + storage_logs + WHERE + hashed_key = ANY ($1) + AND miniblock_number <= $2 + ORDER BY + hashed_key, + miniblock_number DESC, + operation_number DESC + "#, + &bytecode_hashed_keys as &[_], + max_miniblock_number as i64 + ) + .fetch_all(self.storage.conn()) + .await?; + + let deployment_data = rows.into_iter().filter_map(|row| { + if row.value == FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH.as_bytes() { + return None; + } + let miniblock_number = MiniblockNumber(row.miniblock_number as u32); + let address = address_by_hashed_key[row.hashed_key.as_slice()]; + Some((address, miniblock_number)) + }); + Ok(deployment_data.collect()) + } + /// Returns latest values for all [`StorageKey`]s written to in the specified L1 batch /// judging by storage logs (i.e., not taking deduplication logic into account). pub async fn get_touched_slots_for_l1_batch( @@ -1153,4 +1202,144 @@ mod tests { assert!(key_range.contains(&entry.key)); } } + + #[tokio::test] + async fn filtering_deployed_contracts() { + let contract_address = Address::repeat_byte(1); + let other_contract_address = Address::repeat_byte(23); + let successful_deployment = + StorageLog::new_write_log(get_code_key(&contract_address), H256::repeat_byte(0xff)); + let failed_deployment = StorageLog::new_write_log( + get_code_key(&contract_address), + FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, + ); + + let pool = ConnectionPool::test_pool().await; + let mut conn = pool.access_storage().await.unwrap(); + // If deployment fails then two writes are issued, one that writes `bytecode_hash` to the "correct" value, + // and the next write reverts its value back to `FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH`. + conn.storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(1), + &[(H256::zero(), vec![successful_deployment, failed_deployment])], + ) + .await + .unwrap(); + + let tested_miniblocks = [ + None, + Some(MiniblockNumber(0)), + Some(MiniblockNumber(1)), + Some(MiniblockNumber(1)), + ]; + for at_miniblock in tested_miniblocks { + let deployed_map = conn + .storage_logs_dal() + .filter_deployed_contracts( + [contract_address, other_contract_address].into_iter(), + at_miniblock, + ) + .await + .unwrap(); + assert!( + deployed_map.is_empty(), + "{deployed_map:?} at miniblock {at_miniblock:?}" + ); + } + + conn.storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(2), + &[(H256::zero(), vec![successful_deployment])], + ) + .await + .unwrap(); + + for old_miniblock in [MiniblockNumber(0), MiniblockNumber(1)] { + let deployed_map = conn + .storage_logs_dal() + .filter_deployed_contracts( + [contract_address, other_contract_address].into_iter(), + Some(old_miniblock), + ) + .await + .unwrap(); + assert!( + deployed_map.is_empty(), + "{deployed_map:?} at {old_miniblock}" + ); + } + for new_miniblock in [None, Some(MiniblockNumber(2))] { + let deployed_map = conn + .storage_logs_dal() + .filter_deployed_contracts( + [contract_address, other_contract_address].into_iter(), + new_miniblock, + ) + .await + .unwrap(); + assert_eq!( + deployed_map, + HashMap::from([(contract_address, MiniblockNumber(2))]) + ); + } + + let other_successful_deployment = StorageLog::new_write_log( + get_code_key(&other_contract_address), + H256::repeat_byte(0xff), + ); + conn.storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(3), + &[(H256::zero(), vec![other_successful_deployment])], + ) + .await + .unwrap(); + + for old_miniblock in [MiniblockNumber(0), MiniblockNumber(1)] { + let deployed_map = conn + .storage_logs_dal() + .filter_deployed_contracts( + [contract_address, other_contract_address].into_iter(), + Some(old_miniblock), + ) + .await + .unwrap(); + assert!( + deployed_map.is_empty(), + "{deployed_map:?} at miniblock {old_miniblock}" + ); + } + + let deployed_map = conn + .storage_logs_dal() + .filter_deployed_contracts( + [contract_address, other_contract_address].into_iter(), + Some(MiniblockNumber(2)), + ) + .await + .unwrap(); + assert_eq!( + deployed_map, + HashMap::from([(contract_address, MiniblockNumber(2))]) + ); + + for new_miniblock in [None, Some(MiniblockNumber(3))] { + let deployed_map = conn + .storage_logs_dal() + .filter_deployed_contracts( + [contract_address, other_contract_address].into_iter(), + new_miniblock, + ) + .await + .unwrap(); + assert_eq!( + deployed_map, + HashMap::from([ + (contract_address, MiniblockNumber(2)), + (other_contract_address, MiniblockNumber(3)), + ]) + ); + } + } } diff --git a/core/lib/dal/src/tokens_dal.rs b/core/lib/dal/src/tokens_dal.rs index 8308a91b0e29..67a5bb36728a 100644 --- a/core/lib/dal/src/tokens_dal.rs +++ b/core/lib/dal/src/tokens_dal.rs @@ -1,8 +1,5 @@ use sqlx::types::chrono::Utc; -use zksync_types::{ - tokens::TokenInfo, Address, MiniblockNumber, ACCOUNT_CODE_STORAGE_ADDRESS, - FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, -}; +use zksync_types::{tokens::TokenInfo, Address, MiniblockNumber}; use crate::StorageProcessor; @@ -79,34 +76,25 @@ impl TokensDal<'_, '_> { .collect()) } + /// Removes token records that were deployed after `block_number`. pub async fn rollback_tokens(&mut self, block_number: MiniblockNumber) -> sqlx::Result<()> { + let all_token_addresses = self.get_all_l2_token_addresses().await?; + let token_deployment_data = self + .storage + .storage_logs_dal() + .filter_deployed_contracts(all_token_addresses.into_iter(), None) + .await?; + let token_addresses_to_be_removed: Vec<_> = token_deployment_data + .into_iter() + .filter_map(|(address, deployed_at)| (deployed_at > block_number).then_some(address.0)) + .collect(); sqlx::query!( r#" DELETE FROM tokens WHERE - l2_address IN ( - SELECT - SUBSTRING(key, 12, 20) - FROM - storage_logs - WHERE - storage_logs.address = $1 - AND miniblock_number > $2 - AND NOT EXISTS ( - SELECT - 1 - FROM - storage_logs AS s - WHERE - s.hashed_key = storage_logs.hashed_key - AND (s.miniblock_number, s.operation_number) >= (storage_logs.miniblock_number, storage_logs.operation_number) - AND s.value = $3 - ) - ) + l2_address = ANY ($1) "#, - ACCOUNT_CODE_STORAGE_ADDRESS.as_bytes(), - block_number.0 as i64, - FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH.as_bytes() + &token_addresses_to_be_removed as &[_] ) .execute(self.storage.conn()) .await?; @@ -117,37 +105,43 @@ impl TokensDal<'_, '_> { #[cfg(test)] mod tests { - use std::collections::HashSet; + use std::{collections::HashSet, slice}; - use zksync_types::tokens::TokenMetadata; + use zksync_system_constants::FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH; + use zksync_types::{get_code_key, tokens::TokenMetadata, StorageLog, H256}; use super::*; use crate::ConnectionPool; + fn test_token_info() -> TokenInfo { + TokenInfo { + l1_address: Address::repeat_byte(1), + l2_address: Address::repeat_byte(2), + metadata: TokenMetadata { + name: "Test".to_string(), + symbol: "TST".to_string(), + decimals: 10, + }, + } + } + + fn eth_token_info() -> TokenInfo { + TokenInfo { + l1_address: Address::repeat_byte(0), + l2_address: Address::repeat_byte(0), + metadata: TokenMetadata { + name: "Ether".to_string(), + symbol: "ETH".to_string(), + decimals: 18, + }, + } + } + #[tokio::test] async fn adding_and_getting_tokens() { let pool = ConnectionPool::test_pool().await; let mut storage = pool.access_storage().await.unwrap(); - let tokens = [ - TokenInfo { - l1_address: Address::repeat_byte(1), - l2_address: Address::repeat_byte(2), - metadata: TokenMetadata { - name: "Test".to_string(), - symbol: "TST".to_string(), - decimals: 10, - }, - }, - TokenInfo { - l1_address: Address::repeat_byte(0), - l2_address: Address::repeat_byte(0), - metadata: TokenMetadata { - name: "Ether".to_string(), - symbol: "ETH".to_string(), - decimals: 18, - }, - }, - ]; + let tokens = [test_token_info(), eth_token_info()]; storage.tokens_dal().add_tokens(&tokens).await.unwrap(); let token_addresses = storage @@ -163,6 +157,15 @@ mod tests { .collect::>(), ); + let all_tokens = storage + .tokens_web3_dal() + .get_all_tokens(None) + .await + .unwrap(); + assert_eq!(all_tokens.len(), 2); + assert!(all_tokens.contains(&tokens[0])); + assert!(all_tokens.contains(&tokens[1])); + for token in &tokens { storage .tokens_dal() @@ -180,4 +183,161 @@ mod tests { assert!(well_known_tokens.contains(&tokens[0])); assert!(well_known_tokens.contains(&tokens[1])); } + + #[tokio::test] + async fn rolling_back_tokens() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + + let eth_info = eth_token_info(); + let eth_deployment_log = + StorageLog::new_write_log(get_code_key(ð_info.l2_address), H256::repeat_byte(1)); + storage + .storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(0), + &[(H256::zero(), vec![eth_deployment_log])], + ) + .await + .unwrap(); + storage + .tokens_dal() + .add_tokens(slice::from_ref(ð_info)) + .await + .unwrap(); + + let test_info = test_token_info(); + let test_deployment_log = + StorageLog::new_write_log(get_code_key(&test_info.l2_address), H256::repeat_byte(2)); + storage + .storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(2), + &[(H256::zero(), vec![test_deployment_log])], + ) + .await + .unwrap(); + storage + .tokens_dal() + .add_tokens(slice::from_ref(&test_info)) + .await + .unwrap(); + + test_getting_all_tokens(&mut storage).await; + + storage + .tokens_dal() + .rollback_tokens(MiniblockNumber(2)) + .await + .unwrap(); + // Should be a no-op. + assert_eq!( + storage + .tokens_dal() + .get_all_l2_token_addresses() + .await + .unwrap(), + [eth_info.l2_address, test_info.l2_address] + ); + + storage + .tokens_dal() + .rollback_tokens(MiniblockNumber(1)) + .await + .unwrap(); + // The custom token should be removed; Ether shouldn't. + assert_eq!( + storage + .tokens_dal() + .get_all_l2_token_addresses() + .await + .unwrap(), + [eth_info.l2_address] + ); + } + + async fn test_getting_all_tokens(storage: &mut StorageProcessor<'_>) { + for at_miniblock in [None, Some(MiniblockNumber(2)), Some(MiniblockNumber(100))] { + let all_tokens = storage + .tokens_web3_dal() + .get_all_tokens(at_miniblock) + .await + .unwrap(); + assert_eq!(all_tokens.len(), 2); + assert!(all_tokens.contains(ð_token_info())); + assert!(all_tokens.contains(&test_token_info())); + } + + for at_miniblock in [MiniblockNumber(0), MiniblockNumber(1)] { + let all_tokens = storage + .tokens_web3_dal() + .get_all_tokens(Some(at_miniblock)) + .await + .unwrap(); + assert_eq!(all_tokens, [eth_token_info()]); + } + } + + #[tokio::test] + async fn rolling_back_tokens_with_failed_deployment() { + let pool = ConnectionPool::test_pool().await; + let mut storage = pool.access_storage().await.unwrap(); + + let test_info = test_token_info(); + + // Emulate failed deployment. + let failed_deployment_log = StorageLog::new_write_log( + get_code_key(&test_info.l2_address), + FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, + ); + storage + .storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(1), + &[(H256::zero(), vec![failed_deployment_log])], + ) + .await + .unwrap(); + + let test_deployment_log = + StorageLog::new_write_log(get_code_key(&test_info.l2_address), H256::repeat_byte(2)); + storage + .storage_logs_dal() + .insert_storage_logs( + MiniblockNumber(100), + &[(H256::zero(), vec![test_deployment_log])], + ) + .await + .unwrap(); + storage + .tokens_dal() + .add_tokens(slice::from_ref(&test_info)) + .await + .unwrap(); + + // Sanity check: before rollback the token must be present. + assert_eq!( + storage + .tokens_dal() + .get_all_l2_token_addresses() + .await + .unwrap(), + [test_info.l2_address] + ); + + storage + .tokens_dal() + .rollback_tokens(MiniblockNumber(99)) + .await + .unwrap(); + // Token must be removed despite it's failed deployment being earlier than the last retained miniblock. + assert_eq!( + storage + .tokens_dal() + .get_all_l2_token_addresses() + .await + .unwrap(), + [] + ); + } } diff --git a/core/lib/dal/src/tokens_web3_dal.rs b/core/lib/dal/src/tokens_web3_dal.rs index 36f58c2711b4..5bd3cab089ee 100644 --- a/core/lib/dal/src/tokens_web3_dal.rs +++ b/core/lib/dal/src/tokens_web3_dal.rs @@ -1,18 +1,43 @@ use zksync_types::{ tokens::{TokenInfo, TokenMetadata}, - Address, + Address, MiniblockNumber, }; use crate::StorageProcessor; +#[derive(Debug)] +struct StorageTokenInfo { + l1_address: Vec, + l2_address: Vec, + name: String, + symbol: String, + decimals: i32, +} + +impl From for TokenInfo { + fn from(row: StorageTokenInfo) -> Self { + Self { + l1_address: Address::from_slice(&row.l1_address), + l2_address: Address::from_slice(&row.l2_address), + metadata: TokenMetadata { + name: row.name, + symbol: row.symbol, + decimals: row.decimals as u8, + }, + } + } +} + #[derive(Debug)] pub struct TokensWeb3Dal<'a, 'c> { pub(crate) storage: &'a mut StorageProcessor<'c>, } impl TokensWeb3Dal<'_, '_> { + /// Returns information about well-known tokens. pub async fn get_well_known_tokens(&mut self) -> sqlx::Result> { - let records = sqlx::query!( + let records = sqlx::query_as!( + StorageTokenInfo, r#" SELECT l1_address, @@ -31,17 +56,45 @@ impl TokensWeb3Dal<'_, '_> { .fetch_all(self.storage.conn()) .await?; - Ok(records - .into_iter() - .map(|record| TokenInfo { - l1_address: Address::from_slice(&record.l1_address), - l2_address: Address::from_slice(&record.l2_address), - metadata: TokenMetadata { - name: record.name, - symbol: record.symbol, - decimals: record.decimals as u8, - }, - }) - .collect()) + Ok(records.into_iter().map(Into::into).collect()) + } + + /// Returns information about all tokens. + pub async fn get_all_tokens( + &mut self, + at_miniblock: Option, + ) -> sqlx::Result> { + let records = sqlx::query_as!( + StorageTokenInfo, + r#" + SELECT + l1_address, + l2_address, + NAME, + symbol, + decimals + FROM + tokens + ORDER BY + symbol + "# + ) + .fetch_all(self.storage.conn()) + .await?; + + let mut all_tokens: Vec<_> = records.into_iter().map(TokenInfo::from).collect(); + let Some(at_miniblock) = at_miniblock else { + return Ok(all_tokens); // No additional filtering is required + }; + + let token_addresses = all_tokens.iter().map(|token| token.l2_address); + let filtered_addresses = self + .storage + .storage_logs_dal() + .filter_deployed_contracts(token_addresses, Some(at_miniblock)) + .await?; + + all_tokens.retain(|token| filtered_addresses.contains_key(&token.l2_address)); + Ok(all_tokens) } } diff --git a/core/lib/snapshots_applier/src/lib.rs b/core/lib/snapshots_applier/src/lib.rs index 473686fe04f9..b503d3b39112 100644 --- a/core/lib/snapshots_applier/src/lib.rs +++ b/core/lib/snapshots_applier/src/lib.rs @@ -13,6 +13,7 @@ use zksync_types::{ SnapshotFactoryDependencies, SnapshotHeader, SnapshotRecoveryStatus, SnapshotStorageLog, SnapshotStorageLogsChunk, SnapshotStorageLogsStorageKey, }, + tokens::TokenInfo, web3::futures, MiniblockNumber, H256, }; @@ -92,7 +93,7 @@ pub enum SnapshotsApplierOutcome { Ok, /// Main node does not have any ready snapshots. NoSnapshotsOnMainNode, - /// The node was initialized without a snapshot. Detected by the presence of the genesis L1 batch in Postgres. + /// The node was initialized without a snapshot. Detected by the presence of L1 batches in Postgres. InitializedWithoutSnapshot, } @@ -105,6 +106,11 @@ pub trait SnapshotsApplierMainNodeClient: fmt::Debug + Send + Sync { ) -> EnrichedClientResult>; async fn fetch_newest_snapshot(&self) -> EnrichedClientResult>; + + async fn fetch_tokens( + &self, + at_miniblock: MiniblockNumber, + ) -> EnrichedClientResult>; } #[async_trait] @@ -132,6 +138,16 @@ impl SnapshotsApplierMainNodeClient for HttpClient { .with_arg("number", newest_snapshot) .await } + + async fn fetch_tokens( + &self, + at_miniblock: MiniblockNumber, + ) -> EnrichedClientResult> { + self.sync_tokens(Some(at_miniblock)) + .rpc_context("sync_tokens") + .with_arg("miniblock_number", &at_miniblock) + .await + } } /// Snapshot applier configuration options. @@ -208,6 +224,7 @@ impl SnapshotsApplierConfig { #[derive(Debug)] struct SnapshotsApplier<'a> { connection_pool: &'a ConnectionPool, + main_node_client: &'a dyn SnapshotsApplierMainNodeClient, blob_store: &'a dyn ObjectStore, applied_snapshot_status: SnapshotRecoveryStatus, } @@ -230,13 +247,6 @@ impl<'a> SnapshotsApplier<'a> { })?; if let Some(applied_snapshot_status) = applied_snapshot_status { - if !applied_snapshot_status - .storage_logs_chunks_processed - .contains(&false) - { - return Err(SnapshotsApplierOutcome::Ok.into()); - } - let latency = latency.observe(); tracing::info!("Re-initialized snapshots applier after reset/failure in {latency:?}"); @@ -265,7 +275,7 @@ impl<'a> SnapshotsApplier<'a> { async fn load_snapshot( connection_pool: &'a ConnectionPool, - main_node_client: &dyn SnapshotsApplierMainNodeClient, + main_node_client: &'a dyn SnapshotsApplierMainNodeClient, blob_store: &'a dyn ObjectStore, ) -> Result<(), SnapshotsApplierError> { let mut storage = connection_pool @@ -281,6 +291,7 @@ impl<'a> SnapshotsApplier<'a> { let mut recovery = Self { connection_pool, + main_node_client, blob_store, applied_snapshot_status, }; @@ -315,6 +326,7 @@ impl<'a> SnapshotsApplier<'a> { drop(storage); recovery.recover_storage_logs().await?; + recovery.recover_tokens().await?; Ok(()) } @@ -435,7 +447,7 @@ impl<'a> SnapshotsApplier<'a> { Ok(()) } - #[tracing::instrument(level = "debug", err, skip(self))] + #[tracing::instrument(level = "debug", err, skip(self, semaphore))] async fn recover_storage_logs_single_chunk( &self, semaphore: &Semaphore, @@ -503,7 +515,7 @@ impl<'a> SnapshotsApplier<'a> { Ok(()) } - async fn recover_storage_logs(self) -> Result<(), SnapshotsApplierError> { + async fn recover_storage_logs(&self) -> Result<(), SnapshotsApplierError> { let semaphore = Semaphore::new(self.connection_pool.max_size() as usize); let tasks = self .applied_snapshot_status @@ -518,4 +530,70 @@ impl<'a> SnapshotsApplier<'a> { Ok(()) } + + /// Needs to run after recovering storage logs. + async fn recover_tokens(&self) -> Result<(), SnapshotsApplierError> { + // Check whether tokens are already recovered. + let mut storage = self + .connection_pool + .access_storage_tagged("snapshots_applier") + .await?; + let all_token_addresses = storage + .tokens_dal() + .get_all_l2_token_addresses() + .await + .map_err(|err| SnapshotsApplierError::db(err, "failed fetching L2 token addresses"))?; + if !all_token_addresses.is_empty() { + tracing::info!( + "{} tokens are already present in DB; skipping token recovery", + all_token_addresses.len() + ); + return Ok(()); + } + drop(storage); + + let snapshot_miniblock_number = self.applied_snapshot_status.miniblock_number; + let tokens = self + .main_node_client + .fetch_tokens(snapshot_miniblock_number) + .await?; + tracing::info!("Retrieved {} tokens from main node", tokens.len()); + + // Check that all tokens returned by the main node were indeed successfully deployed. + let l2_addresses = tokens.iter().map(|token| token.l2_address); + let mut storage = self + .connection_pool + .access_storage_tagged("snapshots_applier") + .await?; + let filtered_addresses = storage + .storage_logs_dal() + .filter_deployed_contracts(l2_addresses, Some(snapshot_miniblock_number)) + .await + .map_err(|err| { + SnapshotsApplierError::db(err, "failed querying L2 contracts for tokens") + })?; + + let bogus_tokens = tokens.iter().filter(|token| { + // We need special handling for L2 ether; its `l2_address` doesn't have a deployed contract + !token.l2_address.is_zero() && !filtered_addresses.contains_key(&token.l2_address) + }); + let bogus_tokens: Vec<_> = bogus_tokens.collect(); + if !bogus_tokens.is_empty() { + let err = anyhow::anyhow!( + "Main node returned bogus tokens that are not deployed on L2: {bogus_tokens:?}" + ); + return Err(SnapshotsApplierError::Retryable(err)); + } + + tracing::info!( + "Checked {} tokens deployment on L2; persisting tokens into DB", + tokens.len() + ); + storage + .tokens_dal() + .add_tokens(&tokens) + .await + .map_err(|err| SnapshotsApplierError::db(err, "failed persisting tokens"))?; + Ok(()) + } } diff --git a/core/lib/snapshots_applier/src/tests/mod.rs b/core/lib/snapshots_applier/src/tests/mod.rs index 37410111a3c1..80f21aab4d65 100644 --- a/core/lib/snapshots_applier/src/tests/mod.rs +++ b/core/lib/snapshots_applier/src/tests/mod.rs @@ -7,13 +7,14 @@ use test_casing::test_casing; use zksync_object_store::ObjectStoreFactory; use zksync_types::{ block::{L1BatchHeader, MiniblockHeader}, - Address, L1BatchNumber, ProtocolVersion, ProtocolVersionId, + get_code_key, Address, L1BatchNumber, ProtocolVersion, ProtocolVersionId, }; use self::utils::{ mock_recovery_status, prepare_clients, MockMainNodeClient, ObjectStoreWithErrors, }; use super::*; +use crate::tests::utils::{mock_tokens, random_storage_logs}; mod utils; @@ -29,7 +30,12 @@ async fn snapshots_creator_can_successfully_recover_db( ConnectionPool::test_pool().await }; let expected_status = mock_recovery_status(); - let (object_store, client, all_snapshot_storage_logs) = prepare_clients(&expected_status).await; + let storage_logs = random_storage_logs(expected_status.l1_batch_number, 200); + let (object_store, client) = prepare_clients(&expected_status, &storage_logs).await; + let storage_logs_by_hashed_key: HashMap<_, _> = storage_logs + .into_iter() + .map(|log| (log.key.hashed_key(), log)) + .collect(); let object_store_with_errors; let object_store: &dyn ObjectStore = if with_object_store_errors { @@ -62,9 +68,9 @@ async fn snapshots_creator_can_successfully_recover_db( .storage_logs_dedup_dal() .dump_all_initial_writes_for_tests() .await; - assert_eq!(all_initial_writes.len(), all_snapshot_storage_logs.len()); + assert_eq!(all_initial_writes.len(), storage_logs_by_hashed_key.len()); for initial_write in all_initial_writes { - let log = &all_snapshot_storage_logs[&initial_write.hashed_key]; + let log = &storage_logs_by_hashed_key[&initial_write.hashed_key]; assert_eq!( initial_write.l1_batch_number, log.l1_batch_number_of_initial_write @@ -76,23 +82,21 @@ async fn snapshots_creator_can_successfully_recover_db( .storage_logs_dal() .dump_all_storage_logs_for_tests() .await; - assert_eq!(all_storage_logs.len(), all_snapshot_storage_logs.len()); + assert_eq!(all_storage_logs.len(), storage_logs_by_hashed_key.len()); for db_log in all_storage_logs { - let expected_log = &all_snapshot_storage_logs[&db_log.hashed_key]; + let expected_log = &storage_logs_by_hashed_key[&db_log.hashed_key]; assert_eq!(db_log.address, *expected_log.key.address()); assert_eq!(db_log.key, *expected_log.key.key()); assert_eq!(db_log.value, expected_log.value); assert_eq!(db_log.miniblock_number, expected_status.miniblock_number); } - // Try recovering again; it should return early. - let err = SnapshotsApplier::load_snapshot(&pool, &client, object_store) + // Try recovering again. + let outcome = SnapshotsApplierConfig::for_tests() + .run(&pool, &client, object_store) .await - .unwrap_err(); - assert_matches!( - err, - SnapshotsApplierError::EarlyReturn(SnapshotsApplierOutcome::Ok) - ); + .unwrap(); + assert_matches!(outcome, SnapshotsApplierOutcome::Ok); } #[tokio::test] @@ -170,7 +174,8 @@ async fn applier_returns_early_without_snapshots() { async fn applier_returns_error_on_fatal_object_store_error() { let pool = ConnectionPool::test_pool().await; let expected_status = mock_recovery_status(); - let (object_store, client, _) = prepare_clients(&expected_status).await; + let storage_logs = random_storage_logs(expected_status.l1_batch_number, 100); + let (object_store, client) = prepare_clients(&expected_status, &storage_logs).await; let object_store = ObjectStoreWithErrors::new(object_store, |_| { Err(ObjectStoreError::KeyNotFound("not found".into())) }); @@ -191,7 +196,8 @@ async fn applier_returns_error_on_fatal_object_store_error() { async fn applier_returns_error_after_too_many_object_store_retries() { let pool = ConnectionPool::test_pool().await; let expected_status = mock_recovery_status(); - let (object_store, client, _) = prepare_clients(&expected_status).await; + let storage_logs = random_storage_logs(expected_status.l1_batch_number, 100); + let (object_store, client) = prepare_clients(&expected_status, &storage_logs).await; let object_store = ObjectStoreWithErrors::new(object_store, |_| { Err(ObjectStoreError::Other("service not available".into())) }); @@ -207,3 +213,55 @@ async fn applier_returns_error_after_too_many_object_store_retries() { ) })); } + +#[tokio::test] +async fn recovering_tokens() { + let pool = ConnectionPool::test_pool().await; + let expected_status = mock_recovery_status(); + let tokens = mock_tokens(); + let mut storage_logs = random_storage_logs(expected_status.l1_batch_number, 200); + for token in &tokens { + if token.l2_address.is_zero() { + continue; + } + storage_logs.push(SnapshotStorageLog { + key: get_code_key(&token.l2_address), + value: H256::random(), + l1_batch_number_of_initial_write: L1BatchNumber(1), + enumeration_index: storage_logs.len() as u64 + 1, + }); + } + let (object_store, mut client) = prepare_clients(&expected_status, &storage_logs).await; + client.tokens_response = tokens.clone(); + + let outcome = SnapshotsApplierConfig::for_tests() + .run(&pool, &client, &object_store) + .await + .unwrap(); + assert_matches!(outcome, SnapshotsApplierOutcome::Ok); + + // Check that tokens are successfully restored. + let mut storage = pool.access_storage().await.unwrap(); + let recovered_tokens = storage + .tokens_web3_dal() + .get_all_tokens(None) + .await + .unwrap(); + // Since we cannot guarantee token ordering, we need to convert them to maps. + let token_map: HashMap<_, _> = tokens + .into_iter() + .map(|token| (token.l2_address, token)) + .collect(); + let recovered_token_map: HashMap<_, _> = recovered_tokens + .into_iter() + .map(|token| (token.l2_address, token)) + .collect(); + assert_eq!(token_map, recovered_token_map); + + // Check that recovering again works and is a no-op. + let outcome = SnapshotsApplierConfig::for_tests() + .run(&pool, &client, &object_store) + .await + .unwrap(); + assert_matches!(outcome, SnapshotsApplierOutcome::Ok); +} diff --git a/core/lib/snapshots_applier/src/tests/utils.rs b/core/lib/snapshots_applier/src/tests/utils.rs index d52ccc8c737e..adf7f8b0955c 100644 --- a/core/lib/snapshots_applier/src/tests/utils.rs +++ b/core/lib/snapshots_applier/src/tests/utils.rs @@ -13,7 +13,8 @@ use zksync_types::{ SnapshotRecoveryStatus, SnapshotStorageLog, SnapshotStorageLogsChunk, SnapshotStorageLogsChunkMetadata, SnapshotStorageLogsStorageKey, }, - AccountTreeId, Bytes, L1BatchNumber, MiniblockNumber, ProtocolVersionId, StorageKey, + tokens::{TokenInfo, TokenMetadata}, + AccountTreeId, Address, Bytes, L1BatchNumber, MiniblockNumber, ProtocolVersionId, StorageKey, StorageValue, H160, H256, }; use zksync_web3_decl::error::EnrichedClientResult; @@ -24,6 +25,7 @@ use crate::SnapshotsApplierMainNodeClient; pub(super) struct MockMainNodeClient { pub fetch_l2_block_responses: HashMap, pub fetch_newest_snapshot_response: Option, + pub tokens_response: Vec, } #[async_trait] @@ -38,6 +40,13 @@ impl SnapshotsApplierMainNodeClient for MockMainNodeClient { async fn fetch_newest_snapshot(&self) -> EnrichedClientResult> { Ok(self.fetch_newest_snapshot_response.clone()) } + + async fn fetch_tokens( + &self, + _at_miniblock: MiniblockNumber, + ) -> EnrichedClientResult> { + Ok(self.tokens_response.clone()) + } } type ValidateFn = dyn Fn(&str) -> Result<(), ObjectStoreError> + Send + Sync; @@ -144,20 +153,19 @@ fn l1_block_metadata(l1_batch_number: L1BatchNumber, root_hash: H256) -> L1Batch } } -fn random_storage_logs( +pub(super) fn random_storage_logs( l1_batch_number: L1BatchNumber, - chunk_id: u64, - logs_per_chunk: u64, + count: u64, ) -> Vec { - (0..logs_per_chunk) - .map(|x| SnapshotStorageLog { + (0..count) + .map(|i| SnapshotStorageLog { key: StorageKey::new( AccountTreeId::from_fixed_bytes(H160::random().to_fixed_bytes()), H256::random(), ), value: StorageValue::random(), l1_batch_number_of_initial_write: l1_batch_number, - enumeration_index: x + chunk_id * logs_per_chunk, + enumeration_index: i + 1, }) .collect() } @@ -175,13 +183,33 @@ pub(super) fn mock_recovery_status() -> SnapshotRecoveryStatus { } } +pub(super) fn mock_tokens() -> Vec { + vec![ + TokenInfo { + l1_address: Address::zero(), + l2_address: Address::zero(), + metadata: TokenMetadata { + name: "Ether".to_string(), + symbol: "ETH".to_string(), + decimals: 18, + }, + }, + TokenInfo { + l1_address: Address::random(), + l2_address: Address::random(), + metadata: TokenMetadata { + name: "Test".to_string(), + symbol: "TST".to_string(), + decimals: 10, + }, + }, + ] +} + pub(super) async fn prepare_clients( status: &SnapshotRecoveryStatus, -) -> ( - Arc, - MockMainNodeClient, - HashMap, -) { + logs: &[SnapshotStorageLog], +) -> (Arc, MockMainNodeClient) { let object_store_factory = ObjectStoreFactory::mock(); let object_store = object_store_factory.create_store().await; let mut client = MockMainNodeClient::default(); @@ -196,26 +224,23 @@ pub(super) async fn prepare_clients( .await .unwrap(); - let mut all_snapshot_storage_logs = HashMap::::new(); - for chunk_id in 0..status.storage_logs_chunks_processed.len() as u64 { + let chunk_size = logs + .len() + .div_ceil(status.storage_logs_chunks_processed.len()); + assert!(chunk_size > 0); + + for (chunk_id, chunk) in logs.chunks(chunk_size).enumerate() { let chunk_storage_logs = SnapshotStorageLogsChunk { - storage_logs: random_storage_logs(status.l1_batch_number, chunk_id, 10), + storage_logs: chunk.to_vec(), }; let chunk_key = SnapshotStorageLogsStorageKey { l1_batch_number: status.l1_batch_number, - chunk_id, + chunk_id: chunk_id as u64, }; object_store .put(chunk_key, &chunk_storage_logs) .await .unwrap(); - - all_snapshot_storage_logs.extend( - chunk_storage_logs - .storage_logs - .into_iter() - .map(|log| (log.key.hashed_key(), log)), - ); } let snapshot_header = SnapshotHeader { @@ -246,5 +271,5 @@ pub(super) async fn prepare_clients( status.miniblock_hash, ), ); - (object_store, client, all_snapshot_storage_logs) + (object_store, client) } diff --git a/core/lib/web3_decl/src/namespaces/en.rs b/core/lib/web3_decl/src/namespaces/en.rs index 71e40c07eec2..b3aea172f670 100644 --- a/core/lib/web3_decl/src/namespaces/en.rs +++ b/core/lib/web3_decl/src/namespaces/en.rs @@ -1,5 +1,5 @@ use jsonrpsee::{core::RpcResult, proc_macros::rpc}; -use zksync_types::{api::en::SyncBlock, MiniblockNumber}; +use zksync_types::{api::en::SyncBlock, tokens::TokenInfo, MiniblockNumber}; #[cfg_attr( all(feature = "client", feature = "server"), @@ -20,4 +20,11 @@ pub trait EnNamespace { block_number: MiniblockNumber, include_transactions: bool, ) -> RpcResult>; + + /// Lists all tokens created at or before the specified `block_number`. + /// + /// This method is used by EN after snapshot recovery in order to recover token records. + #[method(name = "syncTokens")] + async fn sync_tokens(&self, block_number: Option) + -> RpcResult>; } diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs index 3480c6ec76f0..bb28843bff81 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/en.rs @@ -1,4 +1,4 @@ -use zksync_types::{api::en::SyncBlock, MiniblockNumber}; +use zksync_types::{api::en::SyncBlock, tokens::TokenInfo, MiniblockNumber}; use zksync_web3_decl::{ jsonrpsee::core::{async_trait, RpcResult}, namespaces::en::EnNamespaceServer, @@ -17,4 +17,13 @@ impl EnNamespaceServer for EnNamespace { .await .map_err(into_jsrpc_error) } + + async fn sync_tokens( + &self, + block_number: Option, + ) -> RpcResult> { + self.sync_tokens_impl(block_number) + .await + .map_err(into_jsrpc_error) + } } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs index fdef4f4a36ad..0bb2e2c7dbd9 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/en.rs @@ -1,4 +1,4 @@ -use zksync_types::{api::en::SyncBlock, MiniblockNumber}; +use zksync_types::{api::en::SyncBlock, tokens::TokenInfo, MiniblockNumber}; use zksync_web3_decl::error::Web3Error; use crate::api_server::web3::{backend_jsonrpsee::internal_error, state::RpcState}; @@ -35,4 +35,24 @@ impl EnNamespace { .await .map_err(|err| internal_error(METHOD_NAME, err)) } + + #[tracing::instrument(skip(self))] + pub async fn sync_tokens_impl( + &self, + block_number: Option, + ) -> Result, Web3Error> { + const METHOD_NAME: &str = "sync_tokens"; + + let mut storage = self + .state + .connection_pool + .access_storage_tagged("api") + .await + .map_err(|err| internal_error(METHOD_NAME, err))?; + storage + .tokens_web3_dal() + .get_all_tokens(block_number) + .await + .map_err(|err| internal_error(METHOD_NAME, err)) + } } diff --git a/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts b/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts index e80eb00fbeb9..3d0d48164702 100644 --- a/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts +++ b/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts @@ -2,10 +2,11 @@ import { expect } from 'chai'; import * as protobuf from 'protobufjs'; import * as zlib from 'zlib'; import * as zkweb3 from 'zksync-web3'; -import path from 'node:path'; import fs from 'node:fs/promises'; -import { ChildProcess, spawn, exec } from 'node:child_process'; +import { ChildProcess, spawn, exec, ChildProcessByStdio } from 'node:child_process'; +import path from 'node:path'; import readline from 'node:readline/promises'; +import { Readable, Writable } from 'node:stream'; import { promisify } from 'node:util'; interface AllSnapshotsResponse { @@ -34,6 +35,12 @@ interface StorageLog { readonly enumerationIndex: number; } +interface TokenInfo { + // FIXME: why isn't case changed? + readonly l1_address: string; + readonly l2_address: string; +} + /** * Assumptions: * @@ -51,15 +58,27 @@ describe('snapshot recovery', () => { ...process.env, ZKSYNC_ENV: process.env.IN_DOCKER ? 'ext-node-docker' : 'ext-node' }; + + let snapshotMetadata: GetSnapshotResponse; let mainNode: zkweb3.Provider; + let externalNode: zkweb3.Provider; + let externalNodeProcess: ChildProcessByStdio; before(async () => { expect(process.env.ZKSYNC_ENV, '`ZKSYNC_ENV` should not be set to allow running both server and EN components') .to.be.undefined; mainNode = new zkweb3.Provider('http://127.0.0.1:3050'); + externalNode = new zkweb3.Provider('http://127.0.0.1:3060'); await killExternalNode(); }); + after(async () => { + if (externalNodeProcess) { + externalNodeProcess.kill(); + await killExternalNode(); + } + }); + async function getAllSnapshots() { const output = await mainNode.send('snapshots_getAllSnapshots', []); return output as AllSnapshotsResponse; @@ -70,6 +89,11 @@ describe('snapshot recovery', () => { return output as GetSnapshotResponse; } + async function getAllTokens(provider: zkweb3.Provider, atBlock?: number) { + const output = await provider.send('en_syncTokens', atBlock ? [atBlock] : []); + return output as TokenInfo[]; + } + step('create snapshot', async () => { const logs = await fs.open('snapshot-creator.log', 'w'); const childProcess = spawn('zk run snapshots-creator', { @@ -90,16 +114,16 @@ describe('snapshot recovery', () => { const newBatchNumbers = allSnapshots.snapshotsL1BatchNumbers; const l1BatchNumber = Math.max(...newBatchNumbers); - const fullSnapshot = await getSnapshot(l1BatchNumber); - console.log('Obtained latest snapshot', fullSnapshot); - const miniblockNumber = fullSnapshot.miniblockNumber; + snapshotMetadata = await getSnapshot(l1BatchNumber); + console.log('Obtained latest snapshot', snapshotMetadata); + const miniblockNumber = snapshotMetadata.miniblockNumber; const protoPath = path.join(homeDir, 'core/lib/types/src/proto/mod.proto'); const root = await protobuf.load(protoPath); const SnapshotStorageLogsChunk = root.lookupType('zksync.types.SnapshotStorageLogsChunk'); - expect(fullSnapshot.l1BatchNumber).to.equal(l1BatchNumber); - for (const chunkMetadata of fullSnapshot.storageLogsChunks) { + expect(snapshotMetadata.l1BatchNumber).to.equal(l1BatchNumber); + for (const chunkMetadata of snapshotMetadata.storageLogsChunks) { const chunkPath = path.join(homeDir, chunkMetadata.filepath); console.log(`Checking storage logs chunk ${chunkPath}`); const output = SnapshotStorageLogsChunk.decode(await decompressGzip(chunkPath)) as any as StorageLogChunk; @@ -162,7 +186,7 @@ describe('snapshot recovery', () => { const logs = await fs.open('snapshot-recovery.log', 'a'); await logs.truncate(); - const enProcess = spawn('zk external-node -- --enable-snapshots-recovery', { + externalNodeProcess = spawn('zk external-node -- --enable-snapshots-recovery', { cwd: homeDir, stdio: [null, 'pipe', 'inherit'], shell: true, @@ -171,41 +195,63 @@ describe('snapshot recovery', () => { let consistencyCheckerSucceeded = false; let reorgDetectorSucceeded = false; - try { - const rl = readline.createInterface({ - input: enProcess.stdout, - crlfDelay: Infinity - }); - - // TODO: use a more reliable method to detect recovery success (e.g., based on health checks) - for await (const line of rl) { - if (IMPORTANT_LINE_REGEX.test(line)) { - console.log('en> ' + line); - } - await fs.appendFile(logs, line + '\n'); + const rl = readline.createInterface({ + input: externalNodeProcess.stdout, + crlfDelay: Infinity + }); - if (/L1 batch #\d+ is consistent with L1/.test(line)) { - console.log('Consistency checker successfully checked post-snapshot L1 batch'); - consistencyCheckerSucceeded = true; - } - if (/No reorg at L1 batch #\d+/.test(line)) { - console.log('Reorg detector successfully checked post-snapshot L1 batch'); - reorgDetectorSucceeded = true; - } + // TODO: use a more reliable method to detect recovery success (e.g., based on health checks) + for await (const line of rl) { + if (IMPORTANT_LINE_REGEX.test(line)) { + console.log('en> ' + line); + } + await fs.appendFile(logs, line + '\n'); - if (consistencyCheckerSucceeded && reorgDetectorSucceeded) { - break; - } + if (/L1 batch #\d+ is consistent with L1/.test(line)) { + console.log('Consistency checker successfully checked post-snapshot L1 batch'); + consistencyCheckerSucceeded = true; + } + if (/No reorg at L1 batch #\d+/.test(line)) { + console.log('Reorg detector successfully checked post-snapshot L1 batch'); + reorgDetectorSucceeded = true; } - // If `enProcess` fails early, we'll trip these checks. - expect(enProcess.exitCode).to.be.null; - expect(consistencyCheckerSucceeded, 'consistency check failed').to.be.true; - expect(reorgDetectorSucceeded, 'reorg detection check failed').to.be.true; - } finally { - enProcess.kill(); - await killExternalNode(); + if (consistencyCheckerSucceeded && reorgDetectorSucceeded) { + break; + } } + + // If `externalNodeProcess` fails early, we'll trip these checks. + expect(externalNodeProcess.exitCode).to.be.null; + expect(consistencyCheckerSucceeded, 'consistency check failed').to.be.true; + expect(reorgDetectorSucceeded, 'reorg detection check failed').to.be.true; + }); + + step('check basic EN Web3 endpoints', async () => { + const blockNumber = await externalNode.getBlockNumber(); + console.log(`Block number on EN: ${blockNumber}`); + expect(blockNumber).to.be.greaterThan(snapshotMetadata.miniblockNumber); + const l1BatchNumber = await externalNode.getL1BatchNumber(); + console.log(`L1 batch number on EN: ${l1BatchNumber}`); + expect(l1BatchNumber).to.be.greaterThan(snapshotMetadata.l1BatchNumber); + }); + + step('check tokens on EN', async () => { + const externalNodeTokens = await getAllTokens(externalNode); + console.log('Fetched tokens from EN', externalNodeTokens); + expect(externalNodeTokens).to.not.be.empty; // should contain at least ether + const mainNodeTokens = await getAllTokens(mainNode, snapshotMetadata.miniblockNumber); + console.log('Fetched tokens from main node', mainNodeTokens); + + // Sort tokens deterministically, since the order in which they are returned is not guaranteed. + const compareFn = (x: TokenInfo, y: TokenInfo) => { + expect(x.l2_address, 'Multiple tokens with same L2 address').to.not.equal(y.l2_address); + return x.l2_address < y.l2_address ? -1 : 1; + }; + externalNodeTokens.sort(compareFn); + mainNodeTokens.sort(compareFn); + + expect(mainNodeTokens).to.deep.equal(externalNodeTokens); }); }); From dc2b82706f8b3761a956bcc18c2acd9b77e3e977 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 20 Feb 2024 12:50:37 +0100 Subject: [PATCH 004/106] fix(zk_stack): Use deployer private key and remove create2 address (#1098) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --------- Signed-off-by: Danil --- infrastructure/zk/src/env.ts | 10 ++++++++++ infrastructure/zk/src/hyperchain_wizard.ts | 14 ++++++++++++-- infrastructure/zk/src/init.ts | 19 ++++++++++++++----- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/infrastructure/zk/src/env.ts b/infrastructure/zk/src/env.ts index 9b6eb443636d..835bb4b74cb7 100644 --- a/infrastructure/zk/src/env.ts +++ b/infrastructure/zk/src/env.ts @@ -129,6 +129,16 @@ export function modify(variable: string, assignedVariable: string) { reload(); } +export function removeFromInit(variable: string) { + const initEnv = 'etc/env/.init.env'; + if (!fs.existsSync(initEnv)) { + return; + } + + utils.replaceInFile(initEnv, `${variable}=.*`, ''); + reload(); +} + // merges .init.env with current env file so all configs are in the same place export function mergeInitToEnv() { const env = dotenv.parse(fs.readFileSync(process.env.ENV_FILE!)); diff --git a/infrastructure/zk/src/hyperchain_wizard.ts b/infrastructure/zk/src/hyperchain_wizard.ts index e803b742937a..c80cdf4a76c2 100644 --- a/infrastructure/zk/src/hyperchain_wizard.ts +++ b/infrastructure/zk/src/hyperchain_wizard.ts @@ -64,7 +64,8 @@ async function initHyperchain() { testTokens: { deploy: deployTestTokens, args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] - } + }, + deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey] }; await init(initArgs); @@ -110,6 +111,7 @@ async function setHyperchainMetadata() { BaseNetwork.GOERLI, BaseNetwork.MAINNET ]; + const GENERATE_KEYS = 'Generate keys'; const INSERT_KEYS = 'Insert keys'; const questions: BasePromptOptions[] = [ @@ -139,6 +141,12 @@ async function setHyperchainMetadata() { let deployer, governor, ethOperator, feeReceiver: ethers.Wallet | undefined; let feeReceiverAddress, l1Rpc, l1Id, databaseUrl; + if (results.l1Chain !== BaseNetwork.LOCALHOST || results.l1Chain !== BaseNetwork.LOCALHOST_CUSTOM) { + // If it's not a localhost chain, we need to remove the CONTRACTS_CREATE2_FACTORY_ADDR from the .env file and use default value. + // Otherwise it's a chance that we will reuse create2 factory from the localhost chain. + env.removeFromInit('CONTRACTS_CREATE2_FACTORY_ADDR'); + } + if (results.l1Chain !== BaseNetwork.LOCALHOST) { const connectionsQuestions: BasePromptOptions[] = [ { @@ -195,6 +203,7 @@ async function setHyperchainMetadata() { feeReceiver = ethers.Wallet.createRandom(); feeReceiverAddress = feeReceiver.address; } else { + console.log(warning('The private keys for these wallets must be different from each other!\n')); const keyQuestions: BasePromptOptions[] = [ { message: 'Private key of the L1 Deployer (the one that deploys the contracts)', @@ -788,7 +797,8 @@ async function configDemoHyperchain(cmd: Command) { testTokens: { deploy: deployTestTokens, args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] - } + }, + deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey] }; if (!cmd.skipEnvSetup) { diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index b9abaf415c00..d55c62049f40 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -18,8 +18,14 @@ const success = chalk.green; const timestamp = chalk.grey; export async function init(initArgs: InitArgs = DEFAULT_ARGS) { - const { skipSubmodulesCheckout, skipEnvSetup, testTokens, governorPrivateKeyArgs, deployerL2ContractInput } = - initArgs; + const { + skipSubmodulesCheckout, + skipEnvSetup, + testTokens, + governorPrivateKeyArgs, + deployerPrivateKeyArgs, + deployerL2ContractInput + } = initArgs; if (!process.env.CI && !skipEnvSetup) { await announced('Pulling images', docker.pull()); @@ -41,10 +47,10 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { if (testTokens.deploy) { await announced('Deploying localhost ERC20 tokens', run.deployERC20('dev', '', '', '', testTokens.args)); } - await announced('Deploying L1 verifier', contract.deployVerifier([])); + await announced('Deploying L1 verifier', contract.deployVerifier(deployerPrivateKeyArgs)); await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromSources()); - await announced('Deploying L1 contracts', contract.redeployL1(governorPrivateKeyArgs)); + await announced('Deploying L1 contracts', contract.redeployL1(deployerPrivateKeyArgs)); await announced('Initializing validator', contract.initializeValidator(governorPrivateKeyArgs)); await announced( 'Deploying L2 contracts', @@ -135,6 +141,7 @@ export interface InitArgs { skipSubmodulesCheckout: boolean; skipEnvSetup: boolean; governorPrivateKeyArgs: any[]; + deployerPrivateKeyArgs: any[]; deployerL2ContractInput: { args: any[]; includePaymaster: boolean; @@ -150,6 +157,7 @@ const DEFAULT_ARGS: InitArgs = { skipSubmodulesCheckout: false, skipEnvSetup: false, governorPrivateKeyArgs: [], + deployerPrivateKeyArgs: [], deployerL2ContractInput: { args: [], includePaymaster: true, includeL2WETH: true }, testTokens: { deploy: true, args: [] } }; @@ -164,7 +172,8 @@ export const initCommand = new Command('init') skipEnvSetup: cmd.skipEnvSetup, governorPrivateKeyArgs: [], deployerL2ContractInput: { args: [], includePaymaster: true, includeL2WETH: true }, - testTokens: { deploy: true, args: [] } + testTokens: { deploy: true, args: [] }, + deployerPrivateKeyArgs: [] }; await init(initArgs); }); From 2a766a75db8f14a6eadf0fdecac415865724cb5f Mon Sep 17 00:00:00 2001 From: Lyova Potyomkin Date: Tue, 20 Feb 2024 14:00:07 +0200 Subject: [PATCH 005/106] feat(shared bridge): preparation for shared bridge migration (server) (#1012) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ This PR aims to reduce the diff between main and #298 to simplify the future review. The changes do not affect current server behavior. Only changes related to the zkSync server went into this PR. What didn't go into this PR: - various variable renamings - integration tests - changes that depend on the future version of era-contracts Where applicable, stubs and dummy (for now) config variables were introduced, which can be replaced/populated later. ## Why ❔ Breaking up a PR into smaller chunks should be easier to review. ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --------- Co-authored-by: Bence Haromi <56651250+benceharomi@users.noreply.github.com> Co-authored-by: Bence Haromi --- checks-config/era.dic | 4 + core/bin/external_node/src/config/mod.rs | 5 + core/bin/zksync_server/src/main.rs | 5 + core/lib/config/src/configs/contracts.rs | 12 + core/lib/config/src/testonly.rs | 5 + core/lib/contracts/src/lib.rs | 354 +++--------------- ...de45f8f3f3b6cf2e4136f25a1c3ab85d92668.json | 15 + core/lib/dal/src/protocol_versions_dal.rs | 43 ++- core/lib/env_config/src/chain.rs | 2 + core/lib/env_config/src/contracts.rs | 10 + core/lib/protobuf_config/src/contracts.rs | 50 +++ .../protobuf_config/src/proto/contracts.proto | 5 + core/lib/types/rustfmt.toml | 1 + core/lib/types/src/l2/mod.rs | 3 +- core/lib/types/src/protocol_version.rs | 320 +++++++++------- core/lib/types/src/storage/mod.rs | 3 +- core/lib/types/src/tx/execute.rs | 2 +- core/lib/types/src/zk_evm_types.rs | 8 +- core/lib/web3_decl/src/namespaces/zks.rs | 3 + .../web3/backend_jsonrpsee/namespaces/zks.rs | 4 + .../src/api_server/web3/namespaces/zks.rs | 5 + .../zksync_core/src/api_server/web3/state.rs | 2 + .../src/consistency_checker/mod.rs | 2 +- .../src/eth_sender/eth_tx_aggregator.rs | 126 +++---- core/lib/zksync_core/src/eth_sender/tests.rs | 7 +- .../src/eth_sender/zksync_functions.rs | 52 ++- .../event_processors/governance_upgrades.rs | 14 +- .../eth_watch/event_processors/upgrades.rs | 14 +- core/lib/zksync_core/src/genesis.rs | 42 ++- core/lib/zksync_core/src/lib.rs | 28 +- .../src/state_keeper/io/mempool.rs | 4 +- .../zksync_core/src/state_keeper/keeper.rs | 95 +++-- .../seal_criteria/conditional_sealer.rs | 2 +- .../zksync_core/src/state_keeper/tests/mod.rs | 47 ++- .../src/state_keeper/tests/tester.rs | 28 +- etc/env/base/contracts.toml | 7 + 36 files changed, 722 insertions(+), 607 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json create mode 100644 core/lib/types/rustfmt.toml diff --git a/checks-config/era.dic b/checks-config/era.dic index b5ef3712f51a..22d6189ca671 100644 --- a/checks-config/era.dic +++ b/checks-config/era.dic @@ -411,6 +411,10 @@ prode StorageBatchInfo CommitBatchInfo IExecutor +SetChainId +setChainId +SetChainIdUpgrade +state_transition_manager_contract // Names Vyper diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index e5e61d3f6c10..69b2f6082f99 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -29,6 +29,7 @@ const BYTES_IN_MEGABYTE: usize = 1_024 * 1_024; /// This part of the external node config is fetched directly from the main node. #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct RemoteENConfig { + pub bridgehub_proxy_addr: Option
, pub diamond_proxy_addr: Address, pub l1_erc20_bridge_proxy_addr: Address, pub l2_erc20_bridge_addr: Address, @@ -49,6 +50,8 @@ impl RemoteENConfig { .get_testnet_paymaster() .rpc_context("get_testnet_paymaster") .await?; + // In case EN is connected to the old server version without `get_bridgehub_contract` method. + let bridgehub_proxy_addr = client.get_bridgehub_contract().await.ok().flatten(); let diamond_proxy_addr = client .get_main_contract() .rpc_context("get_main_contract") @@ -60,6 +63,7 @@ impl RemoteENConfig { let l1_chain_id = L1ChainId(l1_chain_id.as_u64()); Ok(Self { + bridgehub_proxy_addr, diamond_proxy_addr, l2_testnet_paymaster_addr, l1_erc20_bridge_proxy_addr: bridges.l1_erc20_default_bridge, @@ -558,6 +562,7 @@ impl From for InternalApiConfig { l1_weth_bridge: config.remote.l1_weth_bridge_proxy_addr, l2_weth_bridge: config.remote.l2_weth_bridge_addr, }, + bridgehub_proxy_addr: config.remote.bridgehub_proxy_addr, diamond_proxy_addr: config.remote.diamond_proxy_addr, l2_testnet_paymaster_addr: config.remote.l2_testnet_paymaster_addr, req_entities_limit: config.optional.req_entities_limit, diff --git a/core/bin/zksync_server/src/main.rs b/core/bin/zksync_server/src/main.rs index a72acdad81d5..fe75a47e7ae2 100644 --- a/core/bin/zksync_server/src/main.rs +++ b/core/bin/zksync_server/src/main.rs @@ -37,6 +37,10 @@ struct Cli { /// Generate genesis block for the first contract deployment using temporary DB. #[arg(long)] genesis: bool, + /// Wait for the `setChainId` event during genesis. + /// If `--genesis` is not set, this flag is ignored. + #[arg(long)] + set_chain_id: bool, /// Rebuild tree. #[arg(long)] rebuild_tree: bool, @@ -142,6 +146,7 @@ async fn main() -> anyhow::Result<()> { &network, &contracts, ð_client.web3_url, + opt.set_chain_id, ) .await .context("genesis_init")?; diff --git a/core/lib/config/src/configs/contracts.rs b/core/lib/config/src/configs/contracts.rs index a05027e0bf0d..70d4e685586f 100644 --- a/core/lib/config/src/configs/contracts.rs +++ b/core/lib/config/src/configs/contracts.rs @@ -40,6 +40,13 @@ pub struct ContractsConfig { pub fri_recursion_leaf_level_vk_hash: H256, pub prover_at_genesis: ProverAtGenesis, pub snark_wrapper_vk_hash: H256, + + // These contracts will be used after shared bridge integration. + pub bridgehub_proxy_addr: Option
, + pub bridgehub_impl_addr: Option
, + pub state_transition_proxy_addr: Option
, + pub state_transition_impl_addr: Option
, + pub transparent_proxy_admin_addr: Option
, } impl ContractsConfig { @@ -52,6 +59,7 @@ impl ContractsConfig { mailbox_facet_addr: Address::repeat_byte(0x01), executor_facet_addr: Address::repeat_byte(0x02), admin_facet_addr: Address::repeat_byte(0x03), + transparent_proxy_admin_addr: Some(Address::repeat_byte(0x04)), getters_facet_addr: Address::repeat_byte(0x05), verifier_addr: Address::repeat_byte(0x06), diamond_init_addr: Address::repeat_byte(0x07), @@ -77,6 +85,10 @@ impl ContractsConfig { governance_addr: Address::repeat_byte(0x13), prover_at_genesis: ProverAtGenesis::Fri, snark_wrapper_vk_hash: H256::repeat_byte(0x09), + bridgehub_proxy_addr: Some(Address::repeat_byte(0x14)), + bridgehub_impl_addr: Some(Address::repeat_byte(0x15)), + state_transition_proxy_addr: Some(Address::repeat_byte(0x16)), + state_transition_impl_addr: Some(Address::repeat_byte(0x17)), } } } diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 3d9fa817bd2b..065e1b3e6054 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -363,6 +363,11 @@ impl RandomConfig for configs::ContractsConfig { fri_recursion_leaf_level_vk_hash: g.gen(), prover_at_genesis: g.gen(), snark_wrapper_vk_hash: g.gen(), + bridgehub_impl_addr: g.gen(), + bridgehub_proxy_addr: g.gen(), + state_transition_proxy_addr: g.gen(), + state_transition_impl_addr: g.gen(), + transparent_proxy_admin_addr: g.gen(), } } } diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index f6bfd9c1e4a3..065008d5dbce 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -11,7 +11,7 @@ use std::{ use ethabi::{ ethereum_types::{H256, U256}, - Contract, Function, + Contract, Event, Function, }; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; @@ -489,358 +489,94 @@ pub static PRE_BOOJUM_COMMIT_FUNCTION: Lazy = Lazy::new(|| { serde_json::from_str(abi).unwrap() }); -pub static PRE_BOOJUM_PROVE_FUNCTION: Lazy = Lazy::new(|| { - let abi = r#" - { +pub static SET_CHAIN_ID_EVENT: Lazy = Lazy::new(|| { + let abi = r#"{ + "anonymous": false, "inputs": [ { - "components": [ - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "indexRepeatedStorageChanges", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "numberOfLayer1Txs", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "priorityOperationsHash", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "l2LogsTreeRoot", - "type": "bytes32" - }, - { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - } - ], - "internalType": "struct IExecutor.StoredBlockInfo", - "name": "_prevBlock", - "type": "tuple" + "indexed": true, + "name": "_stateTransitionChain", + "type": "address" }, { "components": [ { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" - }, - { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" - }, - { - "internalType": "uint64", - "name": "indexRepeatedStorageChanges", - "type": "uint64" + "name": "txType", + "type": "uint256" }, { - "internalType": "uint256", - "name": "numberOfLayer1Txs", + "name": "from", "type": "uint256" }, { - "internalType": "bytes32", - "name": "priorityOperationsHash", - "type": "bytes32" + "name": "to", + "type": "uint256" }, { - "internalType": "bytes32", - "name": "l2LogsTreeRoot", - "type": "bytes32" + "name": "gasLimit", + "type": "uint256" }, { - "internalType": "uint256", - "name": "timestamp", + "name": "gasPerPubdataByteLimit", "type": "uint256" }, { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - } - ], - "internalType": "struct IExecutor.StoredBlockInfo[]", - "name": "_committedBlocks", - "type": "tuple[]" - }, - { - "components": [ - { - "internalType": "uint256[]", - "name": "recursiveAggregationInput", - "type": "uint256[]" + "name": "maxFeePerGas", + "type": "uint256" }, { - "internalType": "uint256[]", - "name": "serializedProof", - "type": "uint256[]" - } - ], - "internalType": "struct IExecutor.ProofInput", - "name": "_proof", - "type": "tuple" - } - ], - "name": "proveBlocks", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }"#; - serde_json::from_str(abi).unwrap() -}); - -pub static PRE_BOOJUM_EXECUTE_FUNCTION: Lazy = Lazy::new(|| { - let abi = r#" - { - "inputs": [ - { - "components": [ - { - "internalType": "uint64", - "name": "blockNumber", - "type": "uint64" + "name": "maxPriorityFeePerGas", + "type": "uint256" }, { - "internalType": "bytes32", - "name": "blockHash", - "type": "bytes32" + "name": "paymaster", + "type": "uint256" }, { - "internalType": "uint64", - "name": "indexRepeatedStorageChanges", - "type": "uint64" + "name": "nonce", + "type": "uint256" }, { - "internalType": "uint256", - "name": "numberOfLayer1Txs", + "name": "value", "type": "uint256" }, { - "internalType": "bytes32", - "name": "priorityOperationsHash", - "type": "bytes32" + "name": "reserved", + "type": "uint256[4]" }, { - "internalType": "bytes32", - "name": "l2LogsTreeRoot", - "type": "bytes32" + "name": "data", + "type": "bytes" }, { - "internalType": "uint256", - "name": "timestamp", - "type": "uint256" + "name": "signature", + "type": "bytes" }, { - "internalType": "bytes32", - "name": "commitment", - "type": "bytes32" - } - ], - "internalType": "struct IExecutor.StoredBlockInfo[]", - "name": "_blocksData", - "type": "tuple[]" - } - ], - "name": "executeBlocks", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }"#; - serde_json::from_str(abi).unwrap() -}); - -pub static PRE_BOOJUM_GET_VK_FUNCTION: Lazy = Lazy::new(|| { - let abi = r#"{ - "inputs": [], - "name": "get_verification_key", - "outputs": [ - { - "components": [ - { - "internalType": "uint256", - "name": "domain_size", - "type": "uint256" + "name": "factoryDeps", + "type": "uint256[]" }, { - "internalType": "uint256", - "name": "num_inputs", - "type": "uint256" + "name": "paymasterInput", + "type": "bytes" }, { - "components": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.Fr", - "name": "omega", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[2]", - "name": "gate_selectors_commitments", - "type": "tuple[2]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[8]", - "name": "gate_setup_commitments", - "type": "tuple[8]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[4]", - "name": "permutation_commitments", - "type": "tuple[4]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point", - "name": "lookup_selector_commitment", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point[4]", - "name": "lookup_tables_commitments", - "type": "tuple[4]" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "X", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "Y", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.G1Point", - "name": "lookup_table_type_commitment", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "internalType": "struct PairingsBn254.Fr[3]", - "name": "non_residues", - "type": "tuple[3]" - }, - { - "components": [ - { - "internalType": "uint256[2]", - "name": "X", - "type": "uint256[2]" - }, - { - "internalType": "uint256[2]", - "name": "Y", - "type": "uint256[2]" - } - ], - "internalType": "struct PairingsBn254.G2Point[2]", - "name": "g2_elements", - "type": "tuple[2]" + "name": "reservedDynamic", + "type": "bytes" } ], - "internalType": "struct VerificationKey", - "name": "vk", + "indexed": false, + "name": "_l2Transaction", "type": "tuple" + }, + { + "indexed": true, + "name": "_protocolVersion", + "type": "uint256" } ], - "stateMutability": "pure", - "type": "function" + "name": "SetChainIdUpgrade", + "type": "event" }"#; serde_json::from_str(abi).unwrap() }); diff --git a/core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json b/core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json new file mode 100644 index 000000000000..1fd7b8fdf1b3 --- /dev/null +++ b/core/lib/dal/.sqlx/query-a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE protocol_versions\n SET\n upgrade_tx_hash = $1\n WHERE\n id = $2\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Bytea", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "a8dad09a54cc991706141da557dde45f8f3f3b6cf2e4136f25a1c3ab85d92668" +} diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 63f09dde5286..7c2079ec4268 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -65,7 +65,7 @@ impl ProtocolVersionsDal<'_, '_> { base_system_contracts_hashes.bootloader.as_bytes(), base_system_contracts_hashes.default_aa.as_bytes(), verifier_address.as_bytes(), - tx_hash.map(|tx_hash| tx_hash.0.to_vec()), + tx_hash.as_ref().map(H256::as_bytes), ) .execute(self.storage.conn()) .await @@ -98,6 +98,47 @@ impl ProtocolVersionsDal<'_, '_> { db_transaction.commit().await.unwrap(); } + async fn save_genesis_upgrade_tx_hash(&mut self, id: ProtocolVersionId, tx_hash: Option) { + sqlx::query!( + r#" + UPDATE protocol_versions + SET + upgrade_tx_hash = $1 + WHERE + id = $2 + "#, + tx_hash.as_ref().map(H256::as_bytes), + id as i32, + ) + .execute(self.storage.conn()) + .await + .unwrap(); + } + + /// Attaches a transaction used to set ChainId to the genesis protocol version. + /// Also inserts that transaction into the database. + pub async fn save_genesis_upgrade_with_tx( + &mut self, + id: ProtocolVersionId, + tx: ProtocolUpgradeTx, + ) { + let tx_hash = Some(tx.common_data.hash()); + + let mut db_transaction = self.storage.start_transaction().await.unwrap(); + + db_transaction + .transactions_dal() + .insert_system_transaction(tx) + .await; + + db_transaction + .protocol_versions_dal() + .save_genesis_upgrade_tx_hash(id, tx_hash) + .await; + + db_transaction.commit().await.unwrap(); + } + pub async fn base_system_contracts_by_timestamp( &mut self, current_timestamp: u64, diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index c258c5092e51..b5028e991076 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -125,6 +125,8 @@ mod tests { CHAIN_STATE_KEEPER_SAVE_CALL_TRACES="false" CHAIN_STATE_KEEPER_UPLOAD_WITNESS_INPUTS_TO_GCS="false" CHAIN_STATE_KEEPER_ENUM_INDEX_MIGRATION_CHUNK_SIZE="2000" + CHAIN_STATE_KEEPER_VIRTUAL_BLOCKS_PER_MINIBLOCK="1" + CHAIN_STATE_KEEPER_VIRTUAL_BLOCKS_INTERVAL="1" "#; lock.set_env(config); diff --git a/core/lib/env_config/src/contracts.rs b/core/lib/env_config/src/contracts.rs index 537b68414c63..bf2dc31d7bb3 100644 --- a/core/lib/env_config/src/contracts.rs +++ b/core/lib/env_config/src/contracts.rs @@ -19,6 +19,10 @@ mod tests { fn expected_config() -> ContractsConfig { ContractsConfig { + bridgehub_proxy_addr: Some(addr("35ea7f92f4c5f433efe15284e99c040110cf6297")), + bridgehub_impl_addr: Some(addr("87d456da9ed212eb49d80d96afb44afddf36adf8")), + state_transition_proxy_addr: Some(addr("d90f1c081c6117241624e97cb6147257c3cb2097")), + state_transition_impl_addr: Some(addr("c957c0e82d3bafb5ad46ffbcc66900648784eb05")), governance_addr: addr("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), mailbox_facet_addr: addr("0f6Fa881EF414Fc6E818180657c2d5CD7Ac6cCAd"), executor_facet_addr: addr("18B631537801963A964211C0E86645c1aBfbB2d3"), @@ -28,6 +32,7 @@ mod tests { diamond_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_upgrade_init_addr: addr("FFC35A5e767BE36057c34586303498e3de7C62Ba"), diamond_proxy_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), + transparent_proxy_admin_addr: Some(addr("dd6fa5c14e7550b4caf2aa2818d24c69cbc347e5")), validator_timelock_addr: addr("F00B988a98Ca742e7958DeF9F7823b5908715f4a"), genesis_tx_hash: hash( "b99ebfea46cbe05a21cd80fe5597d97b204befc52a16303f579c607dc1ac2e2e", @@ -100,6 +105,11 @@ CONTRACTS_FRI_RECURSION_NODE_LEVEL_VK_HASH="0x5a3ef282b21e12fe1f4438e5bb158fc506 CONTRACTS_FRI_RECURSION_LEAF_LEVEL_VK_HASH="0x72167c43a46cf38875b267d67716edc4563861364a3c03ab7aee73498421e828" CONTRACTS_PROVER_AT_GENESIS="fri" CONTRACTS_SNARK_WRAPPER_VK_HASH="0x4be443afd605a782b6e56d199df2460a025c81b3dea144e135bece83612563f2" +CONTRACTS_BRIDGEHUB_PROXY_ADDR="0x35ea7f92f4c5f433efe15284e99c040110cf6297" +CONTRACTS_BRIDGEHUB_IMPL_ADDR="0x87d456da9ed212eb49d80d96afb44afddf36adf8" +CONTRACTS_STATE_TRANSITION_PROXY_ADDR="0xd90f1c081c6117241624e97cb6147257c3cb2097" +CONTRACTS_STATE_TRANSITION_IMPL_ADDR="0xc957c0e82d3bafb5ad46ffbcc66900648784eb05" +CONTRACTS_TRANSPARENT_PROXY_ADMIN_ADDR="0xdd6fa5c14e7550b4caf2aa2818d24c69cbc347e5" "#; lock.set_env(config); diff --git a/core/lib/protobuf_config/src/contracts.rs b/core/lib/protobuf_config/src/contracts.rs index 6521bd0bf810..0a55f9b1145f 100644 --- a/core/lib/protobuf_config/src/contracts.rs +++ b/core/lib/protobuf_config/src/contracts.rs @@ -122,6 +122,36 @@ impl ProtoRepr for proto::Contracts { snark_wrapper_vk_hash: required(&self.snark_wrapper_vk_hash) .and_then(|x| parse_h256(x)) .context("snark_wrapper_vk_hash")?, + bridgehub_proxy_addr: self + .bridgehub_proxy_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("bridgehub_proxy_addr")?, + bridgehub_impl_addr: self + .bridgehub_impl_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("bridgehub_impl_addr")?, + state_transition_proxy_addr: self + .state_transition_proxy_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("state_transition_proxy_addr")?, + state_transition_impl_addr: self + .state_transition_impl_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("state_transition_impl_addr")?, + transparent_proxy_admin_addr: self + .transparent_proxy_admin_addr + .as_ref() + .map(|x| parse_h160(x)) + .transpose() + .context("transparent_proxy_admin_addr")?, }) } @@ -174,6 +204,26 @@ impl ProtoRepr for proto::Contracts { ), prover_at_genesis: Some(proto::ProverAtGenesis::new(&this.prover_at_genesis).into()), snark_wrapper_vk_hash: Some(this.snark_wrapper_vk_hash.as_bytes().into()), + bridgehub_proxy_addr: this + .bridgehub_proxy_addr + .as_ref() + .map(|x| x.as_bytes().into()), + bridgehub_impl_addr: this + .bridgehub_impl_addr + .as_ref() + .map(|x| x.as_bytes().into()), + state_transition_proxy_addr: this + .state_transition_proxy_addr + .as_ref() + .map(|x| x.as_bytes().into()), + state_transition_impl_addr: this + .state_transition_impl_addr + .as_ref() + .map(|x| x.as_bytes().into()), + transparent_proxy_admin_addr: this + .transparent_proxy_admin_addr + .as_ref() + .map(|x| x.as_bytes().into()), } } } diff --git a/core/lib/protobuf_config/src/proto/contracts.proto b/core/lib/protobuf_config/src/proto/contracts.proto index 1acda022cd90..87fd02b615c2 100644 --- a/core/lib/protobuf_config/src/proto/contracts.proto +++ b/core/lib/protobuf_config/src/proto/contracts.proto @@ -36,4 +36,9 @@ message Contracts { optional bytes fri_recursion_leaf_level_vk_hash = 26; // required; H256 optional ProverAtGenesis prover_at_genesis = 27; // required optional bytes snark_wrapper_vk_hash = 28; // required; H256 + optional bytes bridgehub_proxy_addr = 29; // optional; H160 + optional bytes bridgehub_impl_addr = 30; // optional; H160 + optional bytes state_transition_proxy_addr = 31; // optional; H160 + optional bytes state_transition_impl_addr = 32; // optional; H160 + optional bytes transparent_proxy_admin_addr = 33; // optional; H160 } diff --git a/core/lib/types/rustfmt.toml b/core/lib/types/rustfmt.toml new file mode 100644 index 000000000000..d4fcd2a3e948 --- /dev/null +++ b/core/lib/types/rustfmt.toml @@ -0,0 +1 @@ +merge_derives = false diff --git a/core/lib/types/src/l2/mod.rs b/core/lib/types/src/l2/mod.rs index 2498f3490462..a14374728e33 100644 --- a/core/lib/types/src/l2/mod.rs +++ b/core/lib/types/src/l2/mod.rs @@ -22,7 +22,8 @@ use crate::{ pub mod error; -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Serialize, Deserialize, TryFromPrimitive)] #[repr(u32)] pub enum TransactionType { // Native ECDSA Transaction diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 034987d01c81..639ff7f6192b 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -17,9 +17,8 @@ use crate::{ }; #[repr(u16)] -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromPrimitive, Serialize, Deserialize, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(TryFromPrimitive, Serialize, Deserialize)] pub enum ProtocolVersionId { Version0 = 0, Version1, @@ -93,6 +92,15 @@ impl ProtocolVersionId { self <= &Self::Version17 } + pub fn is_pre_shared_bridge(&self) -> bool { + // TODO: review this when we actually deploy shared bridge + true + } + + pub fn is_1_4_0(&self) -> bool { + self >= &ProtocolVersionId::Version18 && self < &ProtocolVersionId::Version20 + } + pub fn is_post_1_4_1(&self) -> bool { self >= &ProtocolVersionId::Version20 } @@ -119,9 +127,8 @@ impl TryFrom for ProtocolVersionId { } #[repr(u16)] -#[derive( - Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, TryFromPrimitive, Serialize, Deserialize, -)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(TryFromPrimitive, Serialize, Deserialize)] pub enum FriProtocolVersionId { Version0 = 0, Version1, @@ -227,6 +234,27 @@ pub struct ProtocolUpgrade { pub tx: Option, } +fn get_transaction_param_type() -> ParamType { + ParamType::Tuple(vec![ + ParamType::Uint(256), // `txType` + ParamType::Uint(256), // sender + ParamType::Uint(256), // to + ParamType::Uint(256), // gasLimit + ParamType::Uint(256), // `gasPerPubdataLimit` + ParamType::Uint(256), // maxFeePerGas + ParamType::Uint(256), // maxPriorityFeePerGas + ParamType::Uint(256), // paymaster + ParamType::Uint(256), // nonce (serial ID) + ParamType::Uint(256), // value + ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved + ParamType::Bytes, // calldata + ParamType::Bytes, // signature + ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps + ParamType::Bytes, // paymaster input + ParamType::Bytes, // `reservedDynamic` + ]) +} + impl TryFrom for ProtocolUpgrade { type Error = crate::ethabi::Error; @@ -252,24 +280,7 @@ impl TryFrom for ProtocolUpgrade { _ => unreachable!(), }; - let transaction_param_type = ParamType::Tuple(vec![ - ParamType::Uint(256), // `txType` - ParamType::Uint(256), // sender - ParamType::Uint(256), // to - ParamType::Uint(256), // gasLimit - ParamType::Uint(256), // `gasPerPubdataLimit` - ParamType::Uint(256), // maxFeePerGas - ParamType::Uint(256), // maxPriorityFeePerGas - ParamType::Uint(256), // paymaster - ParamType::Uint(256), // nonce (serial ID) - ParamType::Uint(256), // value - ParamType::FixedArray(Box::new(ParamType::Uint(256)), 4), // reserved - ParamType::Bytes, // calldata - ParamType::Bytes, // signature - ParamType::Array(Box::new(ParamType::Uint(256))), // factory deps - ParamType::Bytes, // paymaster input - ParamType::Bytes, // `reservedDynamic` - ]); + let transaction_param_type: ParamType = get_transaction_param_type(); let verifier_params_type = ParamType::Tuple(vec![ ParamType::FixedBytes(32), ParamType::FixedBytes(32), @@ -299,119 +310,21 @@ impl TryFrom for ProtocolUpgrade { unreachable!(); }; - let Token::Tuple(mut transaction) = decoded.remove(0) else { + let Token::Tuple(transaction) = decoded.remove(0) else { unreachable!() }; let factory_deps = decoded.remove(0).into_array().unwrap(); - let tx = { - let canonical_tx_hash = H256(keccak256(&encode(&[Token::Tuple(transaction.clone())]))); - - assert_eq!(transaction.len(), 16); - - let tx_type = transaction.remove(0).into_uint().unwrap(); - if tx_type == PROTOCOL_UPGRADE_TX_TYPE.into() { - // There is an upgrade tx. Decoding it. - let sender = transaction.remove(0).into_uint().unwrap(); - let sender = u256_to_account_address(&sender); - - let contract_address = transaction.remove(0).into_uint().unwrap(); - let contract_address = u256_to_account_address(&contract_address); - - let gas_limit = transaction.remove(0).into_uint().unwrap(); - - let gas_per_pubdata_limit = transaction.remove(0).into_uint().unwrap(); - - let max_fee_per_gas = transaction.remove(0).into_uint().unwrap(); - - let max_priority_fee_per_gas = transaction.remove(0).into_uint().unwrap(); - assert_eq!(max_priority_fee_per_gas, U256::zero()); - - let paymaster = transaction.remove(0).into_uint().unwrap(); - let paymaster = u256_to_account_address(&paymaster); - assert_eq!(paymaster, Address::zero()); - - let upgrade_id = transaction.remove(0).into_uint().unwrap(); - - let msg_value = transaction.remove(0).into_uint().unwrap(); - - let reserved = transaction - .remove(0) - .into_fixed_array() - .unwrap() - .into_iter() - .map(|token| token.into_uint().unwrap()) - .collect::>(); - assert_eq!(reserved.len(), 4); - - let to_mint = reserved[0]; - let refund_recipient = u256_to_account_address(&reserved[1]); - - // All other reserved fields should be zero - for item in reserved.iter().skip(2) { - assert_eq!(item, &U256::zero()); - } + let eth_hash = event + .transaction_hash + .expect("Event transaction hash is missing"); + let eth_block = event + .block_number + .expect("Event block number is missing") + .as_u64(); - let calldata = transaction.remove(0).into_bytes().unwrap(); - - let signature = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(signature.len(), 0); - - let _factory_deps_hashes = transaction.remove(0).into_array().unwrap(); - - let paymaster_input = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(paymaster_input.len(), 0); - - // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. - let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); - assert_eq!(reserved_dynamic.len(), 0); - - let eth_hash = event - .transaction_hash - .expect("Event transaction hash is missing"); - let eth_block = event - .block_number - .expect("Event block number is missing") - .as_u64(); - - let common_data = ProtocolUpgradeTxCommonData { - canonical_tx_hash, - sender, - upgrade_id: (upgrade_id.as_u32() as u16).try_into().unwrap(), - to_mint, - refund_recipient, - gas_limit, - max_fee_per_gas, - gas_per_pubdata_limit, - eth_hash, - eth_block, - }; - - let factory_deps = factory_deps - .into_iter() - .map(|t| t.into_bytes().unwrap()) - .collect(); - - let execute = Execute { - contract_address, - calldata: calldata.to_vec(), - factory_deps: Some(factory_deps), - value: msg_value, - }; - - Some(ProtocolUpgradeTx { - common_data, - execute, - received_timestamp_ms: unix_timestamp_ms(), - }) - } else if tx_type == U256::zero() { - // There is no upgrade tx. - None - } else { - panic!("Unexpected tx type {} when decoding upgrade", tx_type); - } - }; + let tx = ProtocolUpgradeTx::decode_tx(transaction, eth_hash, eth_block, factory_deps); let bootloader_code_hash = H256::from_slice(&decoded.remove(0).into_fixed_bytes().unwrap()); let default_account_code_hash = H256::from_slice(&decoded.remove(0).into_fixed_bytes().unwrap()); @@ -458,6 +371,147 @@ impl TryFrom for ProtocolUpgrade { } } +pub fn decode_set_chain_id_event( + event: Log, +) -> Result<(ProtocolVersionId, ProtocolUpgradeTx), crate::ethabi::Error> { + let transaction_param_type: ParamType = get_transaction_param_type(); + + let Token::Tuple(transaction) = decode(&[transaction_param_type], &event.data.0)?.remove(0) + else { + unreachable!() + }; + + let version_id = event.topics[2].to_low_u64_be(); + + let eth_hash = event + .transaction_hash + .expect("Event transaction hash is missing"); + let eth_block = event + .block_number + .expect("Event block number is missing") + .as_u64(); + + let factory_deps: Vec = Vec::new(); + + let upgrade_tx = ProtocolUpgradeTx::decode_tx(transaction, eth_hash, eth_block, factory_deps) + .expect("Upgrade tx is missing"); + let version_id = + ProtocolVersionId::try_from(version_id as u16).expect("Version is not supported"); + + Ok((version_id, upgrade_tx)) +} + +impl ProtocolUpgradeTx { + pub fn decode_tx( + mut transaction: Vec, + eth_hash: H256, + eth_block: u64, + factory_deps: Vec, + ) -> Option { + let canonical_tx_hash = H256(keccak256(&encode(&[Token::Tuple(transaction.clone())]))); + assert_eq!(transaction.len(), 16); + + let tx_type = transaction.remove(0).into_uint().unwrap(); + if tx_type == U256::zero() { + // There is no upgrade tx. + return None; + } + + assert_eq!( + tx_type, + PROTOCOL_UPGRADE_TX_TYPE.into(), + "Unexpected tx type {} when decoding upgrade", + tx_type + ); + + // There is an upgrade tx. Decoding it. + let sender = transaction.remove(0).into_uint().unwrap(); + let sender = u256_to_account_address(&sender); + + let contract_address = transaction.remove(0).into_uint().unwrap(); + let contract_address = u256_to_account_address(&contract_address); + + let gas_limit = transaction.remove(0).into_uint().unwrap(); + + let gas_per_pubdata_limit = transaction.remove(0).into_uint().unwrap(); + + let max_fee_per_gas = transaction.remove(0).into_uint().unwrap(); + + let max_priority_fee_per_gas = transaction.remove(0).into_uint().unwrap(); + assert_eq!(max_priority_fee_per_gas, U256::zero()); + + let paymaster = transaction.remove(0).into_uint().unwrap(); + let paymaster = u256_to_account_address(&paymaster); + assert_eq!(paymaster, Address::zero()); + + let upgrade_id = transaction.remove(0).into_uint().unwrap(); + + let msg_value = transaction.remove(0).into_uint().unwrap(); + + let reserved = transaction + .remove(0) + .into_fixed_array() + .unwrap() + .into_iter() + .map(|token| token.into_uint().unwrap()) + .collect::>(); + assert_eq!(reserved.len(), 4); + + let to_mint = reserved[0]; + let refund_recipient = u256_to_account_address(&reserved[1]); + + // All other reserved fields should be zero + for item in reserved.iter().skip(2) { + assert_eq!(item, &U256::zero()); + } + + let calldata = transaction.remove(0).into_bytes().unwrap(); + + let signature = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(signature.len(), 0); + + let _factory_deps_hashes = transaction.remove(0).into_array().unwrap(); + + let paymaster_input = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(paymaster_input.len(), 0); + + // TODO (SMA-1621): check that `reservedDynamic` are constructed correctly. + let reserved_dynamic = transaction.remove(0).into_bytes().unwrap(); + assert_eq!(reserved_dynamic.len(), 0); + + let common_data = ProtocolUpgradeTxCommonData { + canonical_tx_hash, + sender, + upgrade_id: (upgrade_id.as_u32() as u16).try_into().unwrap(), + to_mint, + refund_recipient, + gas_limit, + max_fee_per_gas, + gas_per_pubdata_limit, + eth_hash, + eth_block, + }; + + let factory_deps = factory_deps + .into_iter() + .map(|t| t.into_bytes().unwrap()) + .collect(); + + let execute = Execute { + contract_address, + calldata: calldata.to_vec(), + factory_deps: Some(factory_deps), + value: msg_value, + }; + + Some(ProtocolUpgradeTx { + common_data, + execute, + received_timestamp_ms: unix_timestamp_ms(), + }) + } +} + impl TryFrom for ProtocolUpgrade { type Error = crate::ethabi::Error; @@ -606,7 +660,7 @@ impl ProtocolVersion { } } -#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ProtocolUpgradeTxCommonData { /// Sender of the transaction. @@ -641,7 +695,7 @@ impl ProtocolUpgradeTxCommonData { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct ProtocolUpgradeTx { pub execute: Execute, pub common_data: ProtocolUpgradeTxCommonData, diff --git a/core/lib/types/src/storage/mod.rs b/core/lib/types/src/storage/mod.rs index 54694f63c504..9d558d013fa0 100644 --- a/core/lib/types/src/storage/mod.rs +++ b/core/lib/types/src/storage/mod.rs @@ -15,7 +15,8 @@ pub use zksync_system_constants::*; use zksync_utils::address_to_h256; /// Typed fully qualified key of the storage slot in global state tree. -#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Serialize, Deserialize)] pub struct StorageKey { account: AccountTreeId, key: H256, diff --git a/core/lib/types/src/tx/execute.rs b/core/lib/types/src/tx/execute.rs index 21f0b401cce2..889c276a3e7a 100644 --- a/core/lib/types/src/tx/execute.rs +++ b/core/lib/types/src/tx/execute.rs @@ -5,7 +5,7 @@ use zksync_utils::ZeroPrefixHexSerde; use crate::{web3::ethabi, Address, EIP712TypedStructure, StructBuilder, H256, U256}; /// `Execute` transaction executes a previously deployed smart contract in the L2 rollup. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct Execute { pub contract_address: Address, diff --git a/core/lib/types/src/zk_evm_types.rs b/core/lib/types/src/zk_evm_types.rs index a7973ab36fec..f165df0c57f5 100644 --- a/core/lib/types/src/zk_evm_types.rs +++ b/core/lib/types/src/zk_evm_types.rs @@ -1,3 +1,4 @@ +use serde::{Deserialize, Serialize}; use zksync_basic_types::{Address, U256}; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -9,12 +10,11 @@ pub enum FarCallOpcode { } /// Struct representing the VM timestamp -#[derive( - Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, PartialOrd, Ord, -)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +#[derive(Serialize, Deserialize)] pub struct Timestamp(pub u32); -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct LogQuery { pub timestamp: Timestamp, pub tx_number_in_block: u16, diff --git a/core/lib/web3_decl/src/namespaces/zks.rs b/core/lib/web3_decl/src/namespaces/zks.rs index 66ca97cb03aa..d62827056232 100644 --- a/core/lib/web3_decl/src/namespaces/zks.rs +++ b/core/lib/web3_decl/src/namespaces/zks.rs @@ -33,6 +33,9 @@ pub trait ZksNamespace { #[method(name = "estimateGasL1ToL2")] async fn estimate_gas_l1_to_l2(&self, req: CallRequest) -> RpcResult; + #[method(name = "getBridgehubContract")] + async fn get_bridgehub_contract(&self) -> RpcResult>; + #[method(name = "getMainContract")] async fn get_main_contract(&self) -> RpcResult
; diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs index e6ef5ddeb907..a3397b39d87a 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/zks.rs @@ -30,6 +30,10 @@ impl ZksNamespaceServer for ZksNamespace { .map_err(into_jsrpc_error) } + async fn get_bridgehub_contract(&self) -> RpcResult> { + Ok(self.get_bridgehub_contract_impl()) + } + async fn get_main_contract(&self) -> RpcResult
{ Ok(self.get_main_contract_impl()) } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs index 61746a20b033..626f747072d5 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs @@ -123,6 +123,11 @@ impl ZksNamespace { .map_err(|err| err.into_web3_error(method_name)) } + #[tracing::instrument(skip(self))] + pub fn get_bridgehub_contract_impl(&self) -> Option
{ + self.state.api_config.bridgehub_proxy_addr + } + #[tracing::instrument(skip(self))] pub fn get_main_contract_impl(&self) -> Address { self.state.api_config.diamond_proxy_addr diff --git a/core/lib/zksync_core/src/api_server/web3/state.rs b/core/lib/zksync_core/src/api_server/web3/state.rs index d930880c4be7..6620d1d664bf 100644 --- a/core/lib/zksync_core/src/api_server/web3/state.rs +++ b/core/lib/zksync_core/src/api_server/web3/state.rs @@ -81,6 +81,7 @@ pub struct InternalApiConfig { pub estimate_gas_scale_factor: f64, pub estimate_gas_acceptable_overestimation: u32, pub bridge_addresses: api::BridgeAddresses, + pub bridgehub_proxy_addr: Option
, pub diamond_proxy_addr: Address, pub l2_testnet_paymaster_addr: Option
, pub req_entities_limit: usize, @@ -106,6 +107,7 @@ impl InternalApiConfig { l1_weth_bridge: contracts_config.l1_weth_bridge_proxy_addr, l2_weth_bridge: contracts_config.l2_weth_bridge_addr, }, + bridgehub_proxy_addr: contracts_config.bridgehub_proxy_addr, diamond_proxy_addr: contracts_config.diamond_proxy_addr, l2_testnet_paymaster_addr: contracts_config.l2_testnet_paymaster_addr, req_entities_limit: web3_config.req_entities_limit(), diff --git a/core/lib/zksync_core/src/consistency_checker/mod.rs b/core/lib/zksync_core/src/consistency_checker/mod.rs index fe49c42b9d3d..40b6eb0314d1 100644 --- a/core/lib/zksync_core/src/consistency_checker/mod.rs +++ b/core/lib/zksync_core/src/consistency_checker/mod.rs @@ -249,7 +249,7 @@ impl ConsistencyChecker { .with_context(|| format!("Commit for tx {commit_tx_hash:?} not found on L1"))? .input; // TODO (PLA-721): Check receiving contract and selector - + // TODO: Add support for post shared bridge commits let commit_function = if local.is_pre_boojum { &*PRE_BOOJUM_COMMIT_FUNCTION } else { diff --git a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs index 3fca8dbcd283..13045119875a 100644 --- a/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs +++ b/core/lib/zksync_core/src/eth_sender/eth_tx_aggregator.rs @@ -7,17 +7,16 @@ use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_eth_client::{BoundEthInterface, CallFunctionArgs}; use zksync_l1_contract_interface::{ multicall3::{Multicall3Call, Multicall3Result}, - pre_boojum_verifier::old_l1_vk_commitment, Detokenize, Tokenizable, Tokenize, }; use zksync_types::{ commitment::SerializeCommitment, eth_sender::EthTx, - ethabi::{Contract, Token}, + ethabi::Token, l2_to_l1_log::UserL2ToL1Log, protocol_version::{L1VerifierConfig, VerifierParams}, web3::contract::Error as Web3ContractError, - Address, ProtocolVersionId, H256, U256, + Address, L2ChainId, ProtocolVersionId, H256, U256, }; use super::aggregated_operations::AggregatedOperation; @@ -53,19 +52,25 @@ pub struct EthTxAggregator { pub(super) main_zksync_contract_address: Address, functions: ZkSyncFunctions, base_nonce: u64, + rollup_chain_id: L2ChainId, } impl EthTxAggregator { - pub fn new( + pub async fn new( config: SenderConfig, aggregator: Aggregator, eth_client: Arc, timelock_contract_address: Address, l1_multicall3_address: Address, main_zksync_contract_address: Address, - base_nonce: u64, + rollup_chain_id: L2ChainId, ) -> Self { let functions = ZkSyncFunctions::default(); + let base_nonce = eth_client + .pending_nonce("eth_sender") + .await + .unwrap() + .as_u64(); Self { config, aggregator, @@ -75,6 +80,7 @@ impl EthTxAggregator { main_zksync_contract_address, functions, base_nonce, + rollup_chain_id, } } @@ -296,34 +302,12 @@ impl EthTxAggregator { async fn get_recursion_scheduler_level_vk_hash( &mut self, verifier_address: Address, - contracts_are_pre_boojum: bool, ) -> Result { - // This is here for backward compatibility with the old verifier: - // Pre-boojum verifier returns the full verification key; - // New verifier returns the hash of the verification key - tracing::debug!("Calling get_verification_key"); - if contracts_are_pre_boojum { - let abi = Contract { - functions: [( - self.functions.get_verification_key.name.clone(), - vec![self.functions.get_verification_key.clone()], - )] - .into(), - ..Default::default() - }; - let args = CallFunctionArgs::new(&self.functions.get_verification_key.name, ()) - .for_contract(verifier_address, abi); - - let vk = self.eth_client.call_contract_function(args).await?; - Ok(old_l1_vk_commitment(Token::from_tokens(vk)?)) - } else { - let get_vk_hash = self.functions.verification_key_hash.as_ref(); - tracing::debug!("Calling verificationKeyHash"); - let args = CallFunctionArgs::new(&get_vk_hash.unwrap().name, ()) - .for_contract(verifier_address, self.functions.verifier_contract.clone()); - let vk_hash = self.eth_client.call_contract_function(args).await?; - Ok(H256::from_tokens(vk_hash)?) - } + let get_vk_hash = &self.functions.verification_key_hash; + let args = CallFunctionArgs::new(&get_vk_hash.name, ()) + .for_contract(verifier_address, self.functions.verifier_contract.clone()); + let vk_hash = self.eth_client.call_contract_function(args).await?; + Ok(H256::from_tokens(vk_hash)?) } #[tracing::instrument(skip(self, storage))] @@ -340,10 +324,10 @@ impl EthTxAggregator { tracing::error!("Failed to get multicall data {err:?}"); err })?; - let contracts_are_pre_boojum = protocol_version_id.is_pre_boojum(); + let contracts_are_pre_shared_bridge = protocol_version_id.is_pre_shared_bridge(); let recursion_scheduler_level_vk_hash = self - .get_recursion_scheduler_level_vk_hash(verifier_address, contracts_are_pre_boojum) + .get_recursion_scheduler_level_vk_hash(verifier_address) .await .map_err(|err| { tracing::error!("Failed to get VK hash from the Verifier {err:?}"); @@ -364,7 +348,7 @@ impl EthTxAggregator { .await { let tx = self - .save_eth_tx(storage, &agg_op, contracts_are_pre_boojum) + .save_eth_tx(storage, &agg_op, contracts_are_pre_shared_bridge) .await?; Self::report_eth_tx_saving(storage, agg_op, &tx).await; } @@ -407,50 +391,64 @@ impl EthTxAggregator { fn encode_aggregated_op( &self, op: &AggregatedOperation, - contracts_are_pre_boojum: bool, + contracts_are_pre_shared_bridge: bool, ) -> Vec { - let operation_is_pre_boojum = op.protocol_version().is_pre_boojum(); + let operation_is_pre_shared_bridge = op.protocol_version().is_pre_shared_bridge(); + assert_eq!( + contracts_are_pre_shared_bridge, + operation_is_pre_shared_bridge + ); + + let mut args = vec![Token::Uint(self.rollup_chain_id.as_u64().into())]; - // For "commit" and "prove" operations it's necessary that the contracts are of the same version as L1 batches are. - // For "execute" it's not required, i.e. we can "execute" pre-boojum batches with post-boojum contracts. match op.clone() { AggregatedOperation::Commit(op) => { - assert_eq!(contracts_are_pre_boojum, operation_is_pre_boojum); - let f = if contracts_are_pre_boojum { - &self.functions.pre_boojum_commit + if contracts_are_pre_shared_bridge { + self.functions + .pre_shared_bridge_commit + .encode_input(&op.into_tokens()) + .expect("Failed to encode commit transaction data") } else { + args.extend(op.into_tokens()); self.functions - .post_boojum_commit + .post_shared_bridge_commit .as_ref() - .expect("Missing ABI for commitBatches") - }; - f.encode_input(&op.into_tokens()) - .expect("Failed to encode commit transaction data") + .expect("Missing ABI for commitBatchesSharedBridge") + .encode_input(&args) + .expect("Failed to encode commit transaction data") + } } AggregatedOperation::PublishProofOnchain(op) => { - assert_eq!(contracts_are_pre_boojum, operation_is_pre_boojum); - let f = if contracts_are_pre_boojum { - &self.functions.pre_boojum_prove + if contracts_are_pre_shared_bridge { + self.functions + .pre_shared_bridge_prove + .encode_input(&op.into_tokens()) + .expect("Failed to encode prove transaction data") } else { + args.extend(op.into_tokens()); self.functions - .post_boojum_prove + .post_shared_bridge_prove .as_ref() - .expect("Missing ABI for proveBatches") - }; - f.encode_input(&op.into_tokens()) - .expect("Failed to encode prove transaction data") + .expect("Missing ABI for proveBatchesSharedBridge") + .encode_input(&args) + .expect("Failed to encode prove transaction data") + } } AggregatedOperation::Execute(op) => { - let f = if contracts_are_pre_boojum { - &self.functions.pre_boojum_execute + if contracts_are_pre_shared_bridge { + self.functions + .pre_shared_bridge_execute + .encode_input(&op.into_tokens()) + .expect("Failed to encode execute transaction data") } else { + args.extend(op.into_tokens()); self.functions - .post_boojum_execute + .post_shared_bridge_execute .as_ref() - .expect("Missing ABI for executeBatches") - }; - f.encode_input(&op.into_tokens()) - .expect("Failed to encode execute transaction data") + .expect("Missing ABI for executeBatchesSharedBridge") + .encode_input(&args) + .expect("Failed to encode execute transaction data") + } } } } @@ -459,11 +457,11 @@ impl EthTxAggregator { &self, storage: &mut StorageProcessor<'_>, aggregated_op: &AggregatedOperation, - contracts_are_pre_boojum: bool, + contracts_are_pre_shared_bridge: bool, ) -> Result { let mut transaction = storage.start_transaction().await.unwrap(); let nonce = self.get_next_nonce(&mut transaction).await?; - let calldata = self.encode_aggregated_op(aggregated_op, contracts_are_pre_boojum); + let calldata = self.encode_aggregated_op(aggregated_op, contracts_are_pre_shared_bridge); let l1_batch_number_range = aggregated_op.l1_batch_range(); let op_type = aggregated_op.get_action_type(); diff --git a/core/lib/zksync_core/src/eth_sender/tests.rs b/core/lib/zksync_core/src/eth_sender/tests.rs index cd5741886add..858f65294401 100644 --- a/core/lib/zksync_core/src/eth_sender/tests.rs +++ b/core/lib/zksync_core/src/eth_sender/tests.rs @@ -111,8 +111,9 @@ impl EthSenderTester { Address::random(), contracts_config.l1_multicall3_addr, Address::random(), - 0, - ); + Default::default(), + ) + .await; let manager = EthTxManager::new( eth_sender_config.sender, @@ -964,7 +965,7 @@ async fn send_operation( .save_eth_tx( &mut tester.conn.access_storage().await.unwrap(), &aggregated_operation, - false, + true, ) .await .unwrap(); diff --git a/core/lib/zksync_core/src/eth_sender/zksync_functions.rs b/core/lib/zksync_core/src/eth_sender/zksync_functions.rs index 8e27af5b628d..00ca15707638 100644 --- a/core/lib/zksync_core/src/eth_sender/zksync_functions.rs +++ b/core/lib/zksync_core/src/eth_sender/zksync_functions.rs @@ -1,17 +1,14 @@ -use zksync_contracts::{ - multicall_contract, verifier_contract, zksync_contract, PRE_BOOJUM_COMMIT_FUNCTION, - PRE_BOOJUM_EXECUTE_FUNCTION, PRE_BOOJUM_GET_VK_FUNCTION, PRE_BOOJUM_PROVE_FUNCTION, -}; +use zksync_contracts::{multicall_contract, verifier_contract, zksync_contract}; use zksync_types::ethabi::{Contract, Function}; #[derive(Debug)] pub(super) struct ZkSyncFunctions { - pub(super) pre_boojum_commit: Function, - pub(super) post_boojum_commit: Option, - pub(super) pre_boojum_prove: Function, - pub(super) post_boojum_prove: Option, - pub(super) pre_boojum_execute: Function, - pub(super) post_boojum_execute: Option, + pub(super) pre_shared_bridge_commit: Function, + pub(super) post_shared_bridge_commit: Option, + pub(super) pre_shared_bridge_prove: Function, + pub(super) post_shared_bridge_prove: Option, + pub(super) pre_shared_bridge_execute: Function, + pub(super) post_shared_bridge_execute: Option, pub(super) get_l2_bootloader_bytecode_hash: Function, pub(super) get_l2_default_account_bytecode_hash: Function, pub(super) get_verifier: Function, @@ -19,8 +16,7 @@ pub(super) struct ZkSyncFunctions { pub(super) get_protocol_version: Function, pub(super) verifier_contract: Contract, - pub(super) get_verification_key: Function, - pub(super) verification_key_hash: Option, + pub(super) verification_key_hash: Function, pub(super) multicall_contract: Contract, pub(super) aggregate3: Function, @@ -50,12 +46,15 @@ impl Default for ZkSyncFunctions { let verifier_contract = verifier_contract(); let multicall_contract = multicall_contract(); - let pre_boojum_commit = PRE_BOOJUM_COMMIT_FUNCTION.clone(); - let post_boojum_commit = get_optional_function(&zksync_contract, "commitBatches"); - let pre_boojum_prove = PRE_BOOJUM_PROVE_FUNCTION.clone(); - let post_boojum_prove = get_optional_function(&zksync_contract, "proveBatches"); - let pre_boojum_execute = PRE_BOOJUM_EXECUTE_FUNCTION.clone(); - let post_boojum_execute = get_optional_function(&zksync_contract, "executeBatches"); + let pre_shared_bridge_commit = get_function(&zksync_contract, "commitBatches"); + let post_shared_bridge_commit = + get_optional_function(&zksync_contract, "commitBatchesSharedBridge"); + let pre_shared_bridge_prove = get_function(&zksync_contract, "proveBatches"); + let post_shared_bridge_prove = + get_optional_function(&zksync_contract, "proveBatchesSharedBridge"); + let pre_shared_bridge_execute = get_function(&zksync_contract, "executeBatches"); + let post_shared_bridge_execute = + get_optional_function(&zksync_contract, "executeBatchesSharedBridge"); let get_l2_bootloader_bytecode_hash = get_function(&zksync_contract, "getL2BootloaderBytecodeHash"); let get_l2_default_account_bytecode_hash = @@ -63,25 +62,22 @@ impl Default for ZkSyncFunctions { let get_verifier = get_function(&zksync_contract, "getVerifier"); let get_verifier_params = get_function(&zksync_contract, "getVerifierParams"); let get_protocol_version = get_function(&zksync_contract, "getProtocolVersion"); - let get_verification_key = PRE_BOOJUM_GET_VK_FUNCTION.clone(); let aggregate3 = get_function(&multicall_contract, "aggregate3"); - let verification_key_hash = - get_optional_function(&verifier_contract, "verificationKeyHash"); + let verification_key_hash = get_function(&verifier_contract, "verificationKeyHash"); ZkSyncFunctions { - pre_boojum_commit, - post_boojum_commit, - pre_boojum_prove, - post_boojum_prove, - pre_boojum_execute, - post_boojum_execute, + pre_shared_bridge_commit, + post_shared_bridge_commit, + pre_shared_bridge_prove, + post_shared_bridge_prove, + pre_shared_bridge_execute, + post_shared_bridge_execute, get_l2_bootloader_bytecode_hash, get_l2_default_account_bytecode_hash, get_verifier, get_verifier_params, get_protocol_version, verifier_contract, - get_verification_key, verification_key_hash, multicall_contract, aggregate3, diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs index 6008f4a05e96..7066838fee88 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/governance_upgrades.rs @@ -76,24 +76,18 @@ impl EventProcessor for GovernanceUpgradesEventProcessor { } } - if upgrades.is_empty() { - return Ok(()); - } - - let ids_str: Vec<_> = upgrades - .iter() - .map(|(u, _)| format!("{}", u.id as u16)) - .collect(); - tracing::debug!("Received upgrades with ids: {}", ids_str.join(", ")); - let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); + if new_upgrades.is_empty() { return Ok(()); } + let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received upgrades with ids: {:?}", ids); + let last_id = new_upgrades.last().unwrap().0.id; let stage_start = Instant::now(); for (upgrade, scheduler_vk_hash) in new_upgrades { diff --git a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs index e7f906cdf070..393dad5afcda 100644 --- a/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs +++ b/core/lib/zksync_core/src/eth_watch/event_processors/upgrades.rs @@ -52,24 +52,18 @@ impl EventProcessor for UpgradesEventProcessor { upgrades.push((upgrade, scheduler_vk_hash)); } - if upgrades.is_empty() { - return Ok(()); - } - - let ids_str: Vec<_> = upgrades - .iter() - .map(|(u, _)| format!("{}", u.id as u16)) - .collect(); - tracing::debug!("Received upgrades with ids: {}", ids_str.join(", ")); - let new_upgrades: Vec<_> = upgrades .into_iter() .skip_while(|(v, _)| v.id as u16 <= self.last_seen_version_id as u16) .collect(); + if new_upgrades.is_empty() { return Ok(()); } + let ids: Vec<_> = new_upgrades.iter().map(|(u, _)| u.id as u16).collect(); + tracing::debug!("Received upgrades with ids: {:?}", ids); + let last_id = new_upgrades.last().unwrap().0.id; let stage_latency = METRICS.poll_eth_node[&PollStage::PersistUpgrades].start(); for (upgrade, scheduler_vk_hash) in new_upgrades { diff --git a/core/lib/zksync_core/src/genesis.rs b/core/lib/zksync_core/src/genesis.rs index 9dfd9b952cee..8b02cc13ba1a 100644 --- a/core/lib/zksync_core/src/genesis.rs +++ b/core/lib/zksync_core/src/genesis.rs @@ -8,9 +8,11 @@ use multivm::{ zk_evm_latest::aux_structures::{LogQuery as MultiVmLogQuery, Timestamp as MultiVMTimestamp}, zkevm_test_harness_latest::witness::sort_storage_access::sort_storage_access_queries, }; -use zksync_contracts::BaseSystemContracts; +use zksync_contracts::{BaseSystemContracts, SET_CHAIN_ID_EVENT}; use zksync_dal::StorageProcessor; +use zksync_eth_client::{clients::QueryClient, EthInterface}; use zksync_merkle_tree::domain::ZkSyncTree; +use zksync_system_constants::PRIORITY_EXPIRATION; use zksync_types::{ block::{ BlockGasCount, DeployedContract, L1BatchHeader, L1BatchTreeData, MiniblockHasher, @@ -19,8 +21,9 @@ use zksync_types::{ commitment::{CommitmentInput, L1BatchCommitment}, fee_model::BatchFeeInput, get_code_key, get_system_context_init_logs, - protocol_version::{L1VerifierConfig, ProtocolVersion}, + protocol_version::{decode_set_chain_id_event, L1VerifierConfig, ProtocolVersion}, tokens::{TokenInfo, TokenMetadata, ETHEREUM_ADDRESS}, + web3::types::{BlockNumber, FilterBuilder}, zk_evm_types::{LogQuery, Timestamp}, AccountTreeId, Address, L1BatchNumber, L2ChainId, MiniblockNumber, ProtocolVersionId, StorageKey, StorageLog, StorageLogKind, H256, @@ -421,6 +424,41 @@ async fn save_genesis_l1_batch_metadata( Ok(()) } +pub(crate) async fn save_set_chain_id_tx( + eth_client_url: &str, + diamond_proxy_address: Address, + state_transition_manager_address: Address, + storage: &mut StorageProcessor<'_>, +) -> anyhow::Result<()> { + let eth_client = QueryClient::new(eth_client_url)?; + let to = eth_client.block_number("fetch_chain_id_tx").await?.as_u64(); + let from = to - PRIORITY_EXPIRATION; + let filter = FilterBuilder::default() + .address(vec![state_transition_manager_address]) + .topics( + Some(vec![SET_CHAIN_ID_EVENT.signature()]), + Some(vec![diamond_proxy_address.into()]), + None, + None, + ) + .from_block(from.into()) + .to_block(BlockNumber::Latest) + .build(); + let mut logs = eth_client.logs(filter, "fetch_chain_id_tx").await?; + anyhow::ensure!( + logs.len() == 1, + "Expected a single set_chain_id event, got these {}: {:?}", + logs.len(), + logs + ); + let (version_id, upgrade_tx) = decode_set_chain_id_event(logs.remove(0))?; + storage + .protocol_versions_dal() + .save_genesis_upgrade_with_tx(version_id, upgrade_tx) + .await; + Ok(()) +} + #[cfg(test)] mod tests { use zksync_dal::ConnectionPool; diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 5575712adda0..4bbbc7551b56 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -29,7 +29,7 @@ use zksync_contracts::{governance_contract, BaseSystemContracts}; use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; use zksync_eth_client::{ clients::{PKSigningClient, QueryClient}, - BoundEthInterface, CallFunctionArgs, EthInterface, + CallFunctionArgs, EthInterface, }; use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; @@ -105,6 +105,7 @@ pub async fn genesis_init( network_config: &NetworkConfig, contracts_config: &ContractsConfig, eth_client_url: &str, + wait_for_set_chain_id: bool, ) -> anyhow::Result<()> { let db_url = postgres_config.master_url()?; let pool = ConnectionPool::singleton(db_url) @@ -176,6 +177,20 @@ pub async fn genesis_init( }, ) .await?; + + if wait_for_set_chain_id { + genesis::save_set_chain_id_tx( + eth_client_url, + contracts_config.diamond_proxy_addr, + contracts_config + .state_transition_proxy_addr + .context("state_transition_proxy_addr is not set, but needed for genesis")?, + &mut storage, + ) + .await + .context("Failed to save SetChainId upgrade transaction")?; + } + Ok(()) } @@ -569,6 +584,7 @@ pub async fn initialize_components( } let main_zksync_contract_address = contracts_config.diamond_proxy_addr; + if components.contains(&Component::EthWatcher) { let started_at = Instant::now(); tracing::info!("initializing ETH-Watcher"); @@ -612,7 +628,6 @@ pub async fn initialize_components( .context("eth_sender_config")?; let eth_client = PKSigningClient::from_config(ð_sender, &contracts_config, ð_client_config); - let nonce = eth_client.pending_nonce("eth_sender").await.unwrap(); let eth_tx_aggregator_actor = EthTxAggregator::new( eth_sender.sender.clone(), Aggregator::new( @@ -623,8 +638,13 @@ pub async fn initialize_components( contracts_config.validator_timelock_addr, contracts_config.l1_multicall3_addr, main_zksync_contract_address, - nonce.as_u64(), - ); + configs + .network_config + .as_ref() + .context("network_config")? + .zksync_network_id, + ) + .await; task_futures.push(tokio::spawn( eth_tx_aggregator_actor.run(eth_sender_pool, stop_receiver.clone()), )); diff --git a/core/lib/zksync_core/src/state_keeper/io/mempool.rs b/core/lib/zksync_core/src/state_keeper/io/mempool.rs index c7597a4aec33..c1ae3474d303 100644 --- a/core/lib/zksync_core/src/state_keeper/io/mempool.rs +++ b/core/lib/zksync_core/src/state_keeper/io/mempool.rs @@ -503,7 +503,7 @@ impl MempoolIO { } async fn wait_for_previous_l1_batch_hash(&self) -> H256 { - tracing::info!( + tracing::trace!( "Getting previous L1 batch hash for L1 batch #{}", self.current_l1_batch_number ); @@ -525,7 +525,7 @@ impl MempoolIO { .unwrap(); wait_latency.observe(); - tracing::info!( + tracing::trace!( "Got previous L1 batch hash: {batch_hash:?} for L1 batch #{}", self.current_l1_batch_number ); diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index 49d269b67f8b..e331aec9763a 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -10,8 +10,11 @@ use multivm::interface::{Halt, L1BatchEnv, SystemEnv}; use tokio::sync::watch; use zksync_dal::ConnectionPool; use zksync_types::{ - block::MiniblockExecutionData, l2::TransactionType, protocol_version::ProtocolUpgradeTx, - storage_writes_deduplicator::StorageWritesDeduplicator, Transaction, + block::MiniblockExecutionData, + l2::TransactionType, + protocol_version::{ProtocolUpgradeTx, ProtocolVersionId}, + storage_writes_deduplicator::StorageWritesDeduplicator, + L1BatchNumber, Transaction, }; use super::{ @@ -31,7 +34,7 @@ pub(super) const POLL_WAIT_DURATION: Duration = Duration::from_secs(1); /// Structure used to indicate that task cancellation was requested. #[derive(thiserror::Error, Debug)] -enum Error { +pub(super) enum Error { #[error("canceled")] Canceled, #[error(transparent)] @@ -148,27 +151,9 @@ impl ZkSyncStateKeeper { let protocol_version = system_env.version; let mut updates_manager = UpdatesManager::new(&l1_batch_env, &system_env); - let previous_batch_protocol_version = - self.io.load_previous_batch_version_id().await.unwrap(); - let version_changed = protocol_version != previous_batch_protocol_version; - - let mut protocol_upgrade_tx = if pending_miniblocks.is_empty() && version_changed { - self.io.load_upgrade_tx(protocol_version).await - } else if !pending_miniblocks.is_empty() && version_changed { - // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block - // then it must be the first one in `txs_to_reexecute`. - if self.io.load_upgrade_tx(protocol_version).await.is_some() { - let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; - assert_eq!( - first_tx_to_reexecute.tx_format(), - TransactionType::ProtocolUpgradeTransaction - ) - } - - None - } else { - None - }; + let mut protocol_upgrade_tx: Option = self + .load_protocol_upgrade_tx(&pending_miniblocks, protocol_version, l1_batch_env.number) + .await?; let mut batch_executor = self .batch_executor_base @@ -232,7 +217,6 @@ impl ZkSyncStateKeeper { .ok_or(Error::Canceled)?; let version_changed = system_env.version != sealed_batch_protocol_version; - protocol_upgrade_tx = if version_changed { self.io.load_upgrade_tx(system_env.version).await } else { @@ -242,6 +226,67 @@ impl ZkSyncStateKeeper { Err(Error::Canceled) } + /// This function is meant to be called only once during the state-keeper initialization. + /// It will check if we should load a protocol upgrade or a `setChainId` transaction, + /// perform some checks and return it. + pub(super) async fn load_protocol_upgrade_tx( + &mut self, + pending_miniblocks: &[MiniblockExecutionData], + protocol_version: ProtocolVersionId, + l1_batch_number: L1BatchNumber, + ) -> Result, Error> { + // After the Shared Bridge is integrated, + // there has to be a setChainId upgrade transaction after the chain genesis. + // It has to be the first transaction of the first batch. + // The setChainId upgrade does not bump the protocol version, but attaches an upgrade + // transaction to the genesis protocol version version. + let first_batch_in_shared_bridge = + l1_batch_number == L1BatchNumber(1) && !protocol_version.is_pre_shared_bridge(); + let previous_batch_protocol_version = + self.io.load_previous_batch_version_id().await.unwrap(); + + let version_changed = protocol_version != previous_batch_protocol_version; + let protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; + + let protocol_upgrade_tx = if pending_miniblocks.is_empty() + && (version_changed || first_batch_in_shared_bridge) + { + // We have a new upgrade transaction - either a regular protocol upgrade or a `setChainId` upgrade. + // If we are running an EN, `protocol_upgrade_tx` will be `None` here since it is fetched from the main node. + tracing::info!( + "There is an new upgrade tx to be executed in batch #{}", + l1_batch_number + ); + protocol_upgrade_tx + } else if !pending_miniblocks.is_empty() + && (version_changed || first_batch_in_shared_bridge) + { + // We already processed the upgrade tx but did not seal the batch it was in. + // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block + // then it must be the first one in `txs_to_reexecute`. + if protocol_upgrade_tx.is_some() { + let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; + assert_eq!( + first_tx_to_reexecute.tx_format(), + TransactionType::ProtocolUpgradeTransaction, + "Expected an upgrade transaction to be the first one in pending_miniblocks, but found {:?}", + first_tx_to_reexecute.hash() + ); + } + tracing::info!( + "There is a protocol upgrade in batch #{}, upgrade tx already processed", + l1_batch_number + ); + None + } else { + // We do not have any upgrade transactions in this batch. + tracing::info!("There is no protocol upgrade in batch #{}", l1_batch_number); + None + }; + + Ok(protocol_upgrade_tx) + } + fn is_canceled(&self) -> bool { *self.stop_receiver.borrow() } diff --git a/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs b/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs index 4e9e797b5a0e..4effb257f027 100644 --- a/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs +++ b/core/lib/zksync_core/src/state_keeper/seal_criteria/conditional_sealer.rs @@ -39,7 +39,7 @@ pub trait ConditionalSealer: 'static + fmt::Debug + Send + Sync { /// /// The checks are deterministic, i.e., should depend solely on execution metrics and [`StateKeeperConfig`]. /// Non-deterministic seal criteria are expressed using [`IoSealCriteria`](super::IoSealCriteria). -#[derive(Debug)] +#[derive(Debug, Default)] pub struct SequencerSealer { config: StateKeeperConfig, sealers: Vec>, diff --git a/core/lib/zksync_core/src/state_keeper/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/tests/mod.rs index 6e18e22ee82c..4de8c3d5ca7f 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/mod.rs @@ -14,6 +14,7 @@ use multivm::{ vm_latest::{constants::BLOCK_GAS_LIMIT, VmExecutionLogs}, }; use once_cell::sync::Lazy; +use tokio::sync::watch; use zksync_config::configs::chain::StateKeeperConfig; use zksync_contracts::BaseSystemContracts; use zksync_system_constants::ZKPORTER_IS_AVAILABLE; @@ -30,8 +31,8 @@ use zksync_types::{ mod tester; use self::tester::{ - bootloader_tip_out_of_gas, pending_batch_data, random_tx, rejected_exec, successful_exec, - successful_exec_with_metrics, TestScenario, + bootloader_tip_out_of_gas, pending_batch_data, random_tx, random_upgrade_tx, rejected_exec, + successful_exec, successful_exec_with_metrics, TestIO, TestScenario, }; pub(crate) use self::tester::{MockBatchExecutor, TestBatchExecutorBuilder}; use crate::{ @@ -44,6 +45,7 @@ use crate::{ }, types::ExecutionMetricsForCriteria, updates::UpdatesManager, + ZkSyncStateKeeper, }, utils::testonly::create_l2_transaction, }; @@ -437,6 +439,47 @@ async fn pending_batch_is_applied() { .await; } +/// Load protocol upgrade transactions +#[tokio::test] +async fn load_upgrade_tx() { + let sealer = SequencerSealer::default(); + let scenario = TestScenario::new(); + let batch_executor_base = TestBatchExecutorBuilder::new(&scenario); + let (stop_sender, stop_receiver) = watch::channel(false); + + let mut io = TestIO::new(stop_sender, scenario); + io.add_upgrade_tx(ProtocolVersionId::latest(), random_upgrade_tx(1)); + io.add_upgrade_tx(ProtocolVersionId::next(), random_upgrade_tx(2)); + + let mut sk = ZkSyncStateKeeper::new( + stop_receiver, + Box::new(io), + Box::new(batch_executor_base), + Arc::new(sealer), + ); + + // Since the version hasn't changed, and we are not using shared bridge, we should not load any + // upgrade transactions. + assert_eq!( + sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::latest(), L1BatchNumber(2)) + .await + .unwrap(), + None + ); + + // If the protocol version has changed, we should load the upgrade transaction. + assert_eq!( + sk.load_protocol_upgrade_tx(&[], ProtocolVersionId::next(), L1BatchNumber(2)) + .await + .unwrap(), + Some(random_upgrade_tx(2)) + ); + + // TODO: add one more test case for the shared bridge after it's integrated. + // If we are processing the 1st batch while using the shared bridge, + // we should load the upgrade transaction -- that's the `SetChainIdUpgrade`. +} + /// Unconditionally seal the batch without triggering specific criteria. #[tokio::test] async fn unconditional_sealing() { diff --git a/core/lib/zksync_core/src/state_keeper/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/tests/tester.rs index 63b96e82dd0e..0f077eacf71b 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/tester.rs @@ -234,6 +234,18 @@ pub(crate) fn random_tx(tx_number: u64) -> Transaction { tx.into() } +/// Creates a random protocol upgrade transaction. Provided tx number would be used as a transaction hash, +/// so it's easier to understand which transaction caused test to fail. +pub(crate) fn random_upgrade_tx(tx_number: u64) -> ProtocolUpgradeTx { + let mut tx = ProtocolUpgradeTx { + execute: Default::default(), + common_data: Default::default(), + received_timestamp_ms: 0, + }; + tx.common_data.canonical_tx_hash = H256::from_low_u64_be(tx_number); + tx +} + /// Creates a `TxExecutionResult` object denoting a successful tx execution. pub(crate) fn successful_exec() -> TxExecutionResult { TxExecutionResult::Success { @@ -385,7 +397,7 @@ pub(crate) struct TestBatchExecutorBuilder { } impl TestBatchExecutorBuilder { - fn new(scenario: &TestScenario) -> Self { + pub(super) fn new(scenario: &TestScenario) -> Self { let mut txs = VecDeque::new(); let mut batch_txs = HashMap::new(); let mut rollback_set = HashSet::new(); @@ -543,7 +555,7 @@ impl TestBatchExecutor { } #[derive(Debug)] -pub(crate) struct TestIO { +pub(super) struct TestIO { stop_sender: watch::Sender, batch_number: L1BatchNumber, timestamp: u64, @@ -556,10 +568,11 @@ pub(crate) struct TestIO { skipping_txs: bool, protocol_version: ProtocolVersionId, previous_batch_protocol_version: ProtocolVersionId, + protocol_upgrade_txs: HashMap, } impl TestIO { - fn new(stop_sender: watch::Sender, scenario: TestScenario) -> Self { + pub(super) fn new(stop_sender: watch::Sender, scenario: TestScenario) -> Self { Self { stop_sender, batch_number: L1BatchNumber(1), @@ -571,9 +584,14 @@ impl TestIO { skipping_txs: false, protocol_version: ProtocolVersionId::latest(), previous_batch_protocol_version: ProtocolVersionId::latest(), + protocol_upgrade_txs: HashMap::default(), } } + pub(super) fn add_upgrade_tx(&mut self, version: ProtocolVersionId, tx: ProtocolUpgradeTx) { + self.protocol_upgrade_txs.insert(version, tx); + } + fn pop_next_item(&mut self, request: &str) -> ScenarioItem { if self.scenario.actions.is_empty() { panic!( @@ -766,9 +784,9 @@ impl StateKeeperIO for TestIO { async fn load_upgrade_tx( &mut self, - _version_id: ProtocolVersionId, + version_id: ProtocolVersionId, ) -> Option { - None + self.protocol_upgrade_txs.get(&version_id).cloned() } } diff --git a/etc/env/base/contracts.toml b/etc/env/base/contracts.toml index bfc9b82aa715..0c8995023e98 100644 --- a/etc/env/base/contracts.toml +++ b/etc/env/base/contracts.toml @@ -48,6 +48,13 @@ PROVER_AT_GENESIS="fri" INITIAL_PROTOCOL_VERSION=18 +# These are currently not used, but will be used once the shared bridge is up +BRIDGEHUB_PROXY_ADDR = "0x0000000000000000000000000000000000000000" +BRIDGEHUB_IMPL_ADDR = "0x0000000000000000000000000000000000000000" +STATE_TRANSITION_PROXY_ADDR = "0x0000000000000000000000000000000000000000" +STATE_TRANSITION_IMPL_ADDR = "0x0000000000000000000000000000000000000000" +TRANSPARENT_PROXY_ADMIN_ADDR = "0x0000000000000000000000000000000000000000" + [contracts.test] dummy_verifier=true easy_priority_mode=false From 22099cb2f90d917a2479b82c8a4165e68c8da878 Mon Sep 17 00:00:00 2001 From: Danil Date: Tue, 20 Feb 2024 13:51:46 +0100 Subject: [PATCH 006/106] feat(en): Take into account nonce from tx proxy (#995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Take into account nonce from TxProxy, now if tx was submitted but miniblock was not synced yet. en will return correct nonce ## Why ❔ [EN doesn't consider ](https://github.com/matter-labs/zksync-era/blob/main/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs#L303)transactions currently residing in the TxProxy when calculating pending nonce, which results in returned nonces being incorrect t times ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --------- Signed-off-by: Danil Co-authored-by: Alex Ostrovski --- ...4e13d46b5ea54a144ec2345a76b865c85f84b.json | 28 ++++ core/lib/dal/src/storage_web3_dal.rs | 26 +++- .../src/api_server/tx_sender/mod.rs | 2 +- .../src/api_server/tx_sender/proxy.rs | 138 ++++++++++++++++-- .../zksync_core/src/api_server/web3/mod.rs | 29 ++-- .../src/api_server/web3/namespaces/eth.rs | 28 +++- .../lib/zksync_core/src/consensus/testonly.rs | 1 + core/lib/zksync_core/src/lib.rs | 6 +- core/lib/zksync_core/src/sync_layer/tests.rs | 1 - .../ts-integration/tests/mempool.test.ts | 5 +- etc/tokens/sepolia.json | 14 -- 11 files changed, 227 insertions(+), 51 deletions(-) create mode 100644 core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json diff --git a/core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json b/core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json new file mode 100644 index 000000000000..d28ef3efdc2e --- /dev/null +++ b/core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json @@ -0,0 +1,28 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n initiator_address,\n MAX(nonce)\n FROM\n transactions\n WHERE\n initiator_address = ANY ($1)\n AND is_priority = FALSE\n AND (\n miniblock_number IS NOT NULL\n OR error IS NULL\n )\n GROUP BY\n initiator_address\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "initiator_address", + "type_info": "Bytea" + }, + { + "ordinal": 1, + "name": "max", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "ByteaArray" + ] + }, + "nullable": [ + false, + null + ] + }, + "hash": "24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b" +} diff --git a/core/lib/dal/src/storage_web3_dal.rs b/core/lib/dal/src/storage_web3_dal.rs index dbb4f2a58b84..573fbe9f53a8 100644 --- a/core/lib/dal/src/storage_web3_dal.rs +++ b/core/lib/dal/src/storage_web3_dal.rs @@ -3,7 +3,7 @@ use std::{collections::HashMap, ops}; use zksync_types::{ get_code_key, get_nonce_key, utils::{decompose_full_nonce, storage_key_for_standard_token_balance}, - AccountTreeId, Address, L1BatchNumber, MiniblockNumber, StorageKey, + AccountTreeId, Address, L1BatchNumber, MiniblockNumber, Nonce, StorageKey, FAILED_CONTRACT_DEPLOYMENT_BYTECODE_HASH, H256, U256, }; use zksync_utils::h256_to_u256; @@ -32,6 +32,30 @@ impl StorageWeb3Dal<'_, '_> { Ok(decompose_full_nonce(full_nonce).0) } + /// Returns the current *stored* nonces (i.e., w/o accounting for pending transactions) for the specified accounts. + pub async fn get_nonces_for_addresses( + &mut self, + addresses: &[Address], + ) -> sqlx::Result> { + let nonce_keys: HashMap<_, _> = addresses + .iter() + .map(|address| (get_nonce_key(address).hashed_key(), *address)) + .collect(); + + let res = self + .get_values(&nonce_keys.keys().copied().collect::>()) + .await? + .into_iter() + .filter_map(|(hashed_key, value)| { + let address = nonce_keys.get(&hashed_key)?; + let full_nonce = h256_to_u256(value); + let (nonce, _) = decompose_full_nonce(full_nonce); + Some((*address, Nonce(nonce.as_u32()))) + }) + .collect(); + Ok(res) + } + pub async fn standard_token_historical_balance( &mut self, token_id: AccountTreeId, diff --git a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs index 51c817b8fbe6..8cf1dd3a96ca 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs @@ -351,7 +351,7 @@ impl TxSender { // We're running an external node: we have to proxy the transaction to the main node. // But before we do that, save the tx to cache in case someone will request it // Before it reaches the main node. - proxy.save_tx(tx.hash(), tx.clone()).await; + proxy.save_tx(tx.clone()).await; proxy.submit_tx(&tx).await?; // Now, after we are sure that the tx is on the main node, remove it from cache // since we don't want to store txs that might have been replaced or otherwise removed diff --git a/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs b/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs index e99899d7cffb..a16ee2d07bbb 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs @@ -1,10 +1,16 @@ -use std::collections::HashMap; +use std::{ + collections::{BTreeSet, HashMap}, + future::Future, + sync::Arc, + time::Duration, +}; -use tokio::sync::RwLock; +use tokio::sync::{watch, RwLock}; +use zksync_dal::ConnectionPool; use zksync_types::{ api::{BlockId, Transaction, TransactionDetails, TransactionId}, l2::L2Tx, - H256, + Address, Nonce, H256, }; use zksync_web3_decl::{ error::{ClientRpcContext, EnrichedClientResult}, @@ -12,11 +18,93 @@ use zksync_web3_decl::{ namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; +#[derive(Debug, Clone, Default)] +pub(crate) struct TxCache { + inner: Arc>, +} + +#[derive(Debug, Default)] +struct TxCacheInner { + tx_cache: HashMap, + nonces_by_account: HashMap>, +} + +impl TxCache { + async fn push(&self, tx: L2Tx) { + let mut inner = self.inner.write().await; + inner + .nonces_by_account + .entry(tx.initiator_account()) + .or_default() + .insert(tx.nonce()); + inner.tx_cache.insert(tx.hash(), tx); + } + + async fn get_tx(&self, tx_hash: H256) -> Option { + self.inner.read().await.tx_cache.get(&tx_hash).cloned() + } + + async fn get_nonces_for_account(&self, account_address: Address) -> BTreeSet { + let inner = self.inner.read().await; + if let Some(nonces) = inner.nonces_by_account.get(&account_address) { + nonces.clone() + } else { + BTreeSet::new() + } + } + + async fn remove_tx(&self, tx_hash: H256) { + self.inner.write().await.tx_cache.remove(&tx_hash); + // We intentionally don't change `nonces_by_account`; they should only be changed in response to new miniblocks + } + + async fn run_updates( + self, + pool: ConnectionPool, + stop_receiver: watch::Receiver, + ) -> anyhow::Result<()> { + const UPDATE_INTERVAL: Duration = Duration::from_secs(1); + + loop { + if *stop_receiver.borrow() { + return Ok(()); + } + + let addresses: Vec<_> = { + // Split into 2 statements for readability. + let inner = self.inner.read().await; + inner.nonces_by_account.keys().copied().collect() + }; + let mut storage = pool.access_storage_tagged("api").await?; + let nonces_for_accounts = storage + .storage_web3_dal() + .get_nonces_for_addresses(&addresses) + .await?; + drop(storage); // Don't hold both `storage` and lock on `inner` at the same time. + + let mut inner = self.inner.write().await; + inner.nonces_by_account.retain(|address, account_nonces| { + let stored_nonce = nonces_for_accounts + .get(address) + .copied() + .unwrap_or(Nonce(0)); + // Retain only nonces starting from the stored one. + *account_nonces = account_nonces.split_off(&stored_nonce); + // If we've removed all nonces, drop the account entry so we don't request stored nonces for it later. + !account_nonces.is_empty() + }); + drop(inner); + + tokio::time::sleep(UPDATE_INTERVAL).await; + } + } +} + /// Used by external node to proxy transaction to the main node /// and store them while they're not synced back yet #[derive(Debug)] pub struct TxProxy { - tx_cache: RwLock>, + tx_cache: TxCache, client: HttpClient, } @@ -25,20 +113,43 @@ impl TxProxy { let client = HttpClientBuilder::default().build(main_node_url).unwrap(); Self { client, - tx_cache: RwLock::new(HashMap::new()), + tx_cache: TxCache::default(), } } pub async fn find_tx(&self, tx_hash: H256) -> Option { - self.tx_cache.read().await.get(&tx_hash).cloned() + self.tx_cache.get_tx(tx_hash).await } pub async fn forget_tx(&self, tx_hash: H256) { - self.tx_cache.write().await.remove(&tx_hash); + self.tx_cache.remove_tx(tx_hash).await; + } + + pub async fn save_tx(&self, tx: L2Tx) { + self.tx_cache.push(tx).await; } - pub async fn save_tx(&self, tx_hash: H256, tx: L2Tx) { - self.tx_cache.write().await.insert(tx_hash, tx); + pub async fn get_nonces_by_account(&self, account_address: Address) -> BTreeSet { + self.tx_cache.get_nonces_for_account(account_address).await + } + + pub async fn next_nonce_by_initiator_account( + &self, + account_address: Address, + current_nonce: u32, + ) -> Nonce { + let mut pending_nonce = Nonce(current_nonce); + let nonces = self.get_nonces_by_account(account_address).await; + for nonce in nonces.range(pending_nonce + 1..) { + // If nonce is not sequential, then we should not increment nonce. + if nonce == &pending_nonce { + pending_nonce += 1; + } else { + break; + } + } + + pending_nonce } pub async fn submit_tx(&self, tx: &L2Tx) -> EnrichedClientResult { @@ -91,4 +202,13 @@ impl TxProxy { .with_arg("hash", &hash) .await } + + pub fn run_account_nonce_sweeper( + &self, + pool: ConnectionPool, + stop_receiver: watch::Receiver, + ) -> impl Future> { + let tx_cache = self.tx_cache.clone(); + tx_cache.run_updates(pool, stop_receiver) + } } diff --git a/core/lib/zksync_core/src/api_server/web3/mod.rs b/core/lib/zksync_core/src/api_server/web3/mod.rs index 7b304f4f2dfb..97eeb790c316 100644 --- a/core/lib/zksync_core/src/api_server/web3/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/mod.rs @@ -122,7 +122,7 @@ struct OptionalApiParams { #[derive(Debug)] struct FullApiParams { pool: ConnectionPool, - last_miniblock_pool: ConnectionPool, + updaters_pool: ConnectionPool, config: InternalApiConfig, transport: ApiTransport, tx_sender: TxSender, @@ -135,7 +135,7 @@ struct FullApiParams { #[derive(Debug)] pub struct ApiBuilder { pool: ConnectionPool, - last_miniblock_pool: ConnectionPool, + updaters_pool: ConnectionPool, config: InternalApiConfig, polling_interval: Duration, // Mandatory params that must be set using builder methods. @@ -153,7 +153,7 @@ impl ApiBuilder { pub fn jsonrpsee_backend(config: InternalApiConfig, pool: ConnectionPool) -> Self { Self { - last_miniblock_pool: pool.clone(), + updaters_pool: pool.clone(), pool, config, polling_interval: Self::DEFAULT_POLLING_INTERVAL, @@ -175,11 +175,12 @@ impl ApiBuilder { self } - /// Configures a dedicated DB pool to be used for updating the latest miniblock information + /// Configures a dedicated DB pool to be used for updating different information, + /// such as last mined block number or account nonces. This pool is used to execute /// in a background task. If not called, the main pool will be used. If the API server is under high load, /// it may make sense to supply a single-connection pool to reduce pool contention with the API methods. - pub fn with_last_miniblock_pool(mut self, pool: ConnectionPool) -> Self { - self.last_miniblock_pool = pool; + pub fn with_updaters_pool(mut self, pool: ConnectionPool) -> Self { + self.updaters_pool = pool; self } @@ -247,7 +248,7 @@ impl ApiBuilder { fn into_full_params(self) -> anyhow::Result { Ok(FullApiParams { pool: self.pool, - last_miniblock_pool: self.last_miniblock_pool, + updaters_pool: self.updaters_pool, config: self.config, transport: self.transport.context("API transport not set")?, tx_sender: self.tx_sender.context("Transaction sender not set")?, @@ -278,10 +279,7 @@ impl FullApiParams { self, last_sealed_miniblock: SealedMiniblockNumber, ) -> anyhow::Result { - let mut storage = self - .last_miniblock_pool - .access_storage_tagged("api") - .await?; + let mut storage = self.updaters_pool.access_storage_tagged("api").await?; let start_info = BlockStartInfo::new(&mut storage).await?; drop(storage); @@ -409,12 +407,17 @@ impl FullApiParams { let (health_check, health_updater) = ReactiveHealthCheck::new(health_check_name); let (last_sealed_miniblock, update_task) = SealedMiniblockNumber::new( - self.last_miniblock_pool.clone(), + self.updaters_pool.clone(), SEALED_MINIBLOCK_UPDATE_INTERVAL, stop_receiver.clone(), ); - let mut tasks = vec![tokio::spawn(update_task)]; + let mut tasks = vec![tokio::spawn(update_task)]; + if let Some(tx_proxy) = &self.tx_sender.0.proxy { + let task = tx_proxy + .run_account_nonce_sweeper(self.updaters_pool.clone(), stop_receiver.clone()); + tasks.push(tokio::spawn(task)); + } let pub_sub = if matches!(transport, ApiTransport::WebSocket(_)) && self.namespaces.contains(&Namespace::Pubsub) { diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs index 86f7e8a56764..5ffbabf834d7 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs @@ -7,8 +7,10 @@ use zksync_types::{ l2::{L2Tx, TransactionType}, transaction_request::CallRequest, utils::decompose_full_nonce, - web3, - web3::types::{FeeHistory, SyncInfo, SyncState}, + web3::{ + self, + types::{FeeHistory, SyncInfo, SyncState}, + }, AccountTreeId, Bytes, MiniblockNumber, StorageKey, H256, L2_ETH_TOKEN_ADDRESS, U256, }; use zksync_utils::u256_to_h256; @@ -302,6 +304,7 @@ impl EthNamespace { const METHOD_NAME: &str = "get_block_transaction_count"; let method_latency = API_METRICS.start_block_call(METHOD_NAME, block_id); + self.state.start_info.ensure_not_pruned(block_id)?; let tx_count = self .state @@ -482,11 +485,22 @@ impl EthNamespace { if matches!(block_id, BlockId::Number(BlockNumber::Pending)) { let account_nonce_u64 = u64::try_from(account_nonce) .map_err(|err| internal_error(method_name, anyhow::anyhow!(err)))?; - account_nonce = connection - .transactions_web3_dal() - .next_nonce_by_initiator_account(address, account_nonce_u64) - .await - .map_err(|err| internal_error(method_name, err))?; + account_nonce = if let Some(proxy) = &self.state.tx_sender.0.proxy { + // EN: get pending nonces from the transaction cache + // We don't have mempool in EN, it's safe to use the proxy cache as a mempool + proxy + .next_nonce_by_initiator_account(address, account_nonce_u64 as u32) + .await + .0 + .into() + } else { + // Main node: get pending nonces from the mempool + connection + .transactions_web3_dal() + .next_nonce_by_initiator_account(address, account_nonce_u64) + .await + .map_err(|err| internal_error(method_name, err))? + }; } let block_diff = self.state.last_sealed_miniblock.diff(block_number); diff --git a/core/lib/zksync_core/src/consensus/testonly.rs b/core/lib/zksync_core/src/consensus/testonly.rs index 8af73f13444b..d0ed762f5e13 100644 --- a/core/lib/zksync_core/src/consensus/testonly.rs +++ b/core/lib/zksync_core/src/consensus/testonly.rs @@ -427,6 +427,7 @@ impl StateKeeperRunner { let (stop_sender, stop_receiver) = sync::watch::channel(false); let (miniblock_sealer, miniblock_sealer_handle) = MiniblockSealer::new(self.pool.clone(), 5); + let io = ExternalIO::new( miniblock_sealer_handle, self.pool.clone(), diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 4bbbc7551b56..baf622375b3a 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -1154,7 +1154,7 @@ async fn run_http_api( } namespaces.push(Namespace::Snapshots); - let last_miniblock_pool = ConnectionPool::singleton(postgres_config.replica_url()?) + let updaters_pool = ConnectionPool::builder(postgres_config.replica_url()?, 2) .build() .await .context("failed to build last_miniblock_pool")?; @@ -1162,7 +1162,7 @@ async fn run_http_api( let api_builder = web3::ApiBuilder::jsonrpsee_backend(internal_api.clone(), replica_connection_pool) .http(api_config.web3_json_rpc.http_port) - .with_last_miniblock_pool(last_miniblock_pool) + .with_updaters_pool(updaters_pool) .with_filter_limit(api_config.web3_json_rpc.filters_limit()) .with_tree_api(api_config.web3_json_rpc.tree_api_url()) .with_batch_request_size_limit(api_config.web3_json_rpc.max_batch_request_size()) @@ -1206,7 +1206,7 @@ async fn run_ws_api( let api_builder = web3::ApiBuilder::jsonrpsee_backend(internal_api.clone(), replica_connection_pool) .ws(api_config.web3_json_rpc.ws_port) - .with_last_miniblock_pool(last_miniblock_pool) + .with_updaters_pool(last_miniblock_pool) .with_filter_limit(api_config.web3_json_rpc.filters_limit()) .with_subscriptions_limit(api_config.web3_json_rpc.subscriptions_limit()) .with_batch_request_size_limit(api_config.web3_json_rpc.max_batch_request_size()) diff --git a/core/lib/zksync_core/src/sync_layer/tests.rs b/core/lib/zksync_core/src/sync_layer/tests.rs index f78a3de84377..eb4745156fc0 100644 --- a/core/lib/zksync_core/src/sync_layer/tests.rs +++ b/core/lib/zksync_core/src/sync_layer/tests.rs @@ -71,7 +71,6 @@ impl StateKeeperHandles { let sync_state = SyncState::default(); let (miniblock_sealer, miniblock_sealer_handle) = MiniblockSealer::new(pool.clone(), 5); tokio::spawn(miniblock_sealer.run()); - let io = ExternalIO::new( miniblock_sealer_handle, pool, diff --git a/core/tests/ts-integration/tests/mempool.test.ts b/core/tests/ts-integration/tests/mempool.test.ts index 160b2a2b81a8..b4fdafd54a61 100644 --- a/core/tests/ts-integration/tests/mempool.test.ts +++ b/core/tests/ts-integration/tests/mempool.test.ts @@ -81,14 +81,15 @@ describe('Tests for the mempool behavior', () => { nonce: startNonce + 1, to: bob.address }); - // First transaction should disappear from the server. - await expect(alice.provider.getTransaction(tx2.hash)).resolves.toBeNull(); // Now fill the gap and see what gets executed await sendTxWithNonce(alice, startNonce).then((tx) => tx.wait()); const replacedReceipt = await replacedTx2.wait(); expect(replacedReceipt.to).toEqual(bob.address); + + // First transaction should disappear from the server. + await expect(alice.provider.getTransaction(tx2.hash)).resolves.toBeNull(); }); test('Should reject a pre-sent transaction with not enough balance', async () => { diff --git a/etc/tokens/sepolia.json b/etc/tokens/sepolia.json index 899571df9e5a..e69de29bb2d1 100644 --- a/etc/tokens/sepolia.json +++ b/etc/tokens/sepolia.json @@ -1,14 +0,0 @@ -[ - { - "name": "DAI", - "symbol": "DAI", - "decimals": 18, - "address": "0x35EfF6eA96571ff475136117FdD92A9ba25b1f37" - }, - { - "name": "Wrapped Ether", - "symbol": "WETH", - "decimals": 18, - "address": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9" - } -] From b567e6c45d341e1188d49810804c9e26be065ab1 Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Tue, 20 Feb 2024 17:15:35 +0200 Subject: [PATCH 007/106] docs(db): Document DB invariants after snapshot recovery (#1133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Documents the invariants after snapshot recovery, e.g. in the DAL crate readme. ## Why ❔ Better DevEx (primarily internal for now). ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [x] Documentation comments have been added / updated. - [x] Code has been formatted via `zk fmt` and `zk lint`. - [x] Spellcheck has been run via `zk spellcheck`. - [x] Linkcheck has been run via `zk linkcheck`. --- ...6387f2f3eda07a630503324bd6576dbdf8231.json | 22 --- ...d425bac8ed3d2780c60c9b63afbcea131f9a0.json | 15 -- core/lib/dal/README.md | 164 ++++++++++++------ core/lib/dal/src/instrument.rs | 11 ++ core/lib/dal/src/transactions_dal.rs | 44 +---- 5 files changed, 127 insertions(+), 129 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231.json delete mode 100644 core/lib/dal/.sqlx/query-f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0.json diff --git a/core/lib/dal/.sqlx/query-3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231.json b/core/lib/dal/.sqlx/query-3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231.json deleted file mode 100644 index ad5c726ea130..000000000000 --- a/core/lib/dal/.sqlx/query-3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n trace\n FROM\n transaction_traces\n WHERE\n tx_hash = $1\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "trace", - "type_info": "Jsonb" - } - ], - "parameters": { - "Left": [ - "Bytea" - ] - }, - "nullable": [ - false - ] - }, - "hash": "3c1d5f985be7e378211aa339c2c6387f2f3eda07a630503324bd6576dbdf8231" -} diff --git a/core/lib/dal/.sqlx/query-f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0.json b/core/lib/dal/.sqlx/query-f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0.json deleted file mode 100644 index c10268b73326..000000000000 --- a/core/lib/dal/.sqlx/query-f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n transaction_traces (tx_hash, trace, created_at, updated_at)\n VALUES\n ($1, $2, NOW(), NOW())\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Bytea", - "Jsonb" - ] - }, - "nullable": [] - }, - "hash": "f922c0718c9dda2f285f09cbabad425bac8ed3d2780c60c9b63afbcea131f9a0" -} diff --git a/core/lib/dal/README.md b/core/lib/dal/README.md index d86aa8c655e1..61bd43489b52 100644 --- a/core/lib/dal/README.md +++ b/core/lib/dal/README.md @@ -3,52 +3,118 @@ This crate provides read and write access to the main database (which is Postgres), that acts as a primary source of truth. -Current schema is managed by `diesel` - that applies all the schema changes from `migrations` directory. - -## Schema - -### Storage tables - -| Table name | Description | Usage | -| ------------ | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | -| storage | Main storage column: mapping from hashed StorageKey (account + key) to the value. | We also store additional columns there (like transaction hash or creation time). | -| storage_logs | Stores all the storage access logs for all the transactions. | Main source of truth - other columns (like `storage`) are created by compacting this column. Its primary index is (storage key, mini_block, operation_id) | - -### Prover queue tables - -The tables below are used by different parts of witness generation. - -| Table name | Description | -| ----------------------------- | ---------------------------------- | -| witness_inputs | TODO | -| leaf_aggregation_witness_jobs | Queue of jobs for leaf aggregation | -| node_aggregation_witness_jobs | Queue of jobs for node aggregation | -| scheduler_witness_jobs | TODO | - -### TODO - -| Table name | -| ------------------------------------- | -| \_sqlx_migrations | -| aggregated_proof | -| contract_verification_requests | -| contract_verification_solc_versions | -| contract_verification_zksolc_versions | -| contracts_verification_info | -| eth_txs | -| eth_txs_history | -| events | -| factory_deps | -| gpu_prover_queue | -| initial_writes | -| l1_batches | -| l2_to_l1_logs | -| miniblocks | -| proof | -| protective_reads | -| prover_jobs | -| static_artifact_storage | -| storage_logs_dedup | -| tokens | -| transaction_traces | -| transactions | +Current schema is managed by `sqlx`. Schema changes are stored in the [`migrations`](migrations) directory. + +## Schema overview + +_This overview skips prover-related and Ethereum sender-related tables, which are specific to the main node._ + +### Miniblocks and L1 batches + +- `miniblocks`. Stores miniblock headers. + +- `miniblocks_consensus`. Stores miniblock data related to the consensus algorithm used by the decentralized sequencer. + Tied one-to-one to miniblocks (the consensus side of the relation is optional). + +- `l1_batches`. Stores L1 batch headers. + +- `commitments`. Stores a part of L1 batch commitment data (event queue and bootloader memory commitments). In the + future, other commitment-related columns will be moved here from `l1_batches`. + +### Transactions + +- `transactions`. Stores all transactions received by the node, both L2 and L1 ones. Transactions in this table are not + necessarily included into a miniblock; i.e., the table is used as a persistent mempool as well. + +### VM storage + +See [`zksync_state`] crate for more context. + +- `storage_logs`. Stores all the VM storage write logs for all transactions, as well as non-transaction writes generated + by the bootloader. This is the source of truth for the VM storage; all other VM storage implementations (see the + [`zksync_state`] crate) are based on it (e.g., by adding persistent or in-memory caching). Used by multiple components + including Metadata calculator, Commitment generator, API server (both for reading one-off values like account balance, + and as a part of the VM sandbox) etc. + +- `initial_writes`. Stores initial writes information for each L1 batch, i.e., the enumeration index assigned for each + key. Used when generating L1 batch metadata in Metadata calculator and Commitment generator components, and in the VM + sandbox in API server for fee estimation. + +- `protective_reads`. Stores protective read information for each L1 batch, i.e., keys influencing VM execution for the + batch that were not modified. Used when generating L1 batch metadata in Commitment generator. + +- `factory_deps`. Stores bytecodes of all deployed L2 contracts. + +- `storage`. **Obsolete, going to be removed; must not be used in new code.** + +### Other VM artifacts + +- `events`. Stores all events (aka logs) emitted by smart contracts during VM execution. + +- `l2_to_l1_logs`. Stores L2-to-L1 logs emitted by smart contracts during VM execution. + +- `call_traces`. Stores call traces for transactions emitted during VM execution. (Unlike with L1 node implementations, + in Era call traces are currently proactively generated for all transactions.) + +- `tokens`. Stores all ERC-20 tokens registered in the L1–L2 bridge. + +- `transaction_traces`. **Obsolete, going to be removed; must not be used in new code.** + +### Snapshot generation and recovery + +See [`snapshots_creator`] and [`snapshots_applier`] crates for the overview of application-level nodes snapshots. + +- `snapshots`. Stores metadata for all snapshots generated by `snapshots_creator`, such as the L1 batch of the snapshot. + +- `snapshot_recovery`. Stores metadata for the snapshot used during node recovery, if any. Currently, this table is + expected to have no more than one row. + +## Logical invariants + +In addition to foreign key constraints and other constraints manifested directly in the DB schema, the following +invariants are expected to be upheld: + +- If a header is present in the `miniblocks` table, it is expected that the DB contains all artifacts associated with + the miniblock execution, such as `events`, `l2_to_l1_logs`, `call_traces`, `tokens` etc. (See State keeper I/O logic + for the exact definition of these artifacts.) +- Likewise, if a header is present in the `l1_batches` table, all artifacts associated with the L1 batch execution are + also expected in the DB, e.g. `initial_writes` and `protective_reads`. (See State keeper I/O logic for the exact + definition of these artifacts.) +- Miniblocks and L1 batches present in the DB form a continuous range of numbers. If a DB is recovered from a node + snapshot, the first miniblock / L1 batch is **the next one** after the snapshot miniblock / L1 batch mentioned in the + `snapshot_recovery` table. Otherwise, miniblocks / L1 batches must start from number 0 (aka genesis). + +## Contributing to DAL + +Some tips and tricks to make contributing to DAL easier: + +- If you want to add a new DB query, search the DAL code or the [`.sqlx`](.sqlx) directory for the identical / + equivalent queries. Reuse is almost always better than duplication. +- It usually makes sense to instrument your queries using [`instrument`](src/instrument.rs) tooling. See the + `instrument` module docs for details. +- It's best to cover added queries with unit tests to ensure they work and don't break in the future. `sqlx` has + compile-time schema checking, but it's not a panacea. +- If there are doubts as to the query performance, run a query with [`EXPLAIN`] / `EXPLAIN ANALYZE` prefixes against a + production-size database. + +### Backward compatibility + +All DB schema changes are expected to be backward-compatible. That is, _old_ code must be able to function with the +_new_ schema. As an example, dropping / renaming columns is not allowed. Instead, a 2-phase migration should be used: + +1. The column should be marked as obsolete, with its mentions replaced in all queries. If the column should be renamed, + a new column should be created and data (if any) should be copied from the old column (see also: + [_Programmatic migrations_](#programmatic-migrations)). +2. After a significant delay (order of months), the old column may be removed in a separate migration. + +### Programmatic migrations + +We cannot afford non-trivial amount of downtime caused by a data migration. That is, if a migration may cause such +downtime (e.g., it copies non-trivial amount of data), it must be organized as a programmatic migration and run in the +node background (perhaps, splitting work into chunks with a delay between them so that the migration doesn't hog all DB +resources). + +[`zksync_state`]: ../state +[`snapshots_creator`]: ../../bin/snapshots_creator +[`snapshots_applier`]: ../snapshots_applier +[`EXPLAIN`]: https://www.postgresql.org/docs/14/sql-explain.html diff --git a/core/lib/dal/src/instrument.rs b/core/lib/dal/src/instrument.rs index ad59d837554b..747423098057 100644 --- a/core/lib/dal/src/instrument.rs +++ b/core/lib/dal/src/instrument.rs @@ -1,4 +1,15 @@ //! DAL query instrumentation. +//! +//! Query instrumentation allows to: +//! +//! - Report query latency as a metric +//! - Report slow and failing queries as metrics +//! - Log slow and failing queries together with their arguments, which makes it easier to debug. +//! +//! The entry point for instrumentation is the [`InstrumentExt`] trait. After it is imported into the scope, +//! its `instrument()` method can be placed on the output of `query*` functions or macros. You can then call +//! [`Instrumented`] methods on the returned struct, e.g. to [report query latency](Instrumented::report_latency()) +//! and/or [to add logged args](Instrumented::with_arg()) for a query. use std::{fmt, future::Future, panic::Location}; diff --git a/core/lib/dal/src/transactions_dal.rs b/core/lib/dal/src/transactions_dal.rs index 364b6e13e301..a37eb72da89c 100644 --- a/core/lib/dal/src/transactions_dal.rs +++ b/core/lib/dal/src/transactions_dal.rs @@ -11,7 +11,7 @@ use zksync_types::{ l2::L2Tx, protocol_version::ProtocolUpgradeTx, tx::{tx_execution_info::TxExecutionStatus, TransactionExecutionResult}, - vm_trace::{Call, VmExecutionTrace}, + vm_trace::Call, Address, ExecuteTransactionCommon, L1BatchNumber, L1BlockNumber, MiniblockNumber, PriorityOpId, Transaction, H256, PROTOCOL_UPGRADE_TX_TYPE, U256, }; @@ -1074,48 +1074,6 @@ impl TransactionsDal<'_, '_> { } } - pub async fn insert_trace(&mut self, hash: H256, trace: VmExecutionTrace) { - { - sqlx::query!( - r#" - INSERT INTO - transaction_traces (tx_hash, trace, created_at, updated_at) - VALUES - ($1, $2, NOW(), NOW()) - "#, - hash.as_bytes(), - serde_json::to_value(trace).unwrap() - ) - .execute(self.storage.conn()) - .await - .unwrap(); - } - } - - pub async fn get_trace(&mut self, hash: H256) -> Option { - { - let trace = sqlx::query!( - r#" - SELECT - trace - FROM - transaction_traces - WHERE - tx_hash = $1 - "#, - hash.as_bytes() - ) - .fetch_optional(self.storage.conn()) - .await - .unwrap() - .map(|record| record.trace); - trace.map(|trace| { - serde_json::from_value(trace) - .unwrap_or_else(|_| panic!("invalid trace json in database for {:?}", hash)) - }) - } - } - /// Returns miniblocks with their transactions that state_keeper needs to re-execute on restart. /// These are the transactions that are included to some miniblock, /// but not included to L1 batch. The order of the transactions is the same as it was From 8b0cc4a81a49d3d8b58bb0e94e5bd20f9fec14d6 Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Tue, 20 Feb 2024 17:33:05 +0100 Subject: [PATCH 008/106] feat(prover): Added 4844 circuit to verification keys (#1141) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Added support for 4844 circuit to verification key generator ## Why ❔ * 4844 is the new circuit that will be used from the upcoming release. --- prover/prover_fri_types/src/lib.rs | 32 +++ .../data/verification_eip4844_key.json | 242 ++++++++++++++++++ .../src/keystore.rs | 41 ++- .../src/main.rs | 9 +- 4 files changed, 312 insertions(+), 12 deletions(-) create mode 100644 prover/vk_setup_data_generator_server_fri/data/verification_eip4844_key.json diff --git a/prover/prover_fri_types/src/lib.rs b/prover/prover_fri_types/src/lib.rs index 0fc979849f2f..9d9c6c1a6ee6 100644 --- a/prover/prover_fri_types/src/lib.rs +++ b/prover/prover_fri_types/src/lib.rs @@ -146,6 +146,38 @@ impl ProverServiceDataKey { round: AggregationRound::Scheduler, } } + + const EIP_4844_CIRCUIT_ID: u8 = 255; + + /// Key for 4844 circuit. + // Currently this is a special 'aux' style circuit (as we have just one), + // But from VM 1.5.0 it will change into a 'basic' circuit. + pub fn eip4844() -> Self { + Self { + circuit_id: Self::EIP_4844_CIRCUIT_ID, + round: AggregationRound::BasicCircuits, + } + } + pub fn is_eip4844(&self) -> bool { + self.circuit_id == Self::EIP_4844_CIRCUIT_ID + && self.round == AggregationRound::BasicCircuits + } + + pub fn name(&self) -> String { + if self.is_eip4844() { + return "eip4844".to_string(); + } + match self.round { + AggregationRound::BasicCircuits => { + format!("basic_{}", self.circuit_id) + } + AggregationRound::LeafAggregation => { + format!("leaf_{}", self.circuit_id) + } + AggregationRound::NodeAggregation => "node".to_string(), + AggregationRound::Scheduler => "scheduler".to_string(), + } + } } #[derive(serde::Serialize, serde::Deserialize)] diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_eip4844_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_eip4844_key.json new file mode 100644 index 000000000000..f0f7aa9b913f --- /dev/null +++ b/prover/vk_setup_data_generator_server_fri/data/verification_eip4844_key.json @@ -0,0 +1,242 @@ +{ + "fixed_parameters": { + "parameters": { + "num_columns_under_copy_permutation": 60, + "num_witness_columns": 0, + "num_constant_columns": 8, + "max_allowed_constraint_degree": 4 + }, + "lookup_parameters": { + "UseSpecializedColumnsWithTableIdAsConstant": { + "width": 3, + "num_repetitions": 20, + "share_table_id": true + } + }, + "domain_size": 1048576, + "total_tables_len": 132096, + "public_inputs_locations": [ + [ + 0, + 871888 + ], + [ + 1, + 871888 + ], + [ + 2, + 871888 + ], + [ + 3, + 871888 + ] + ], + "extra_constant_polys_for_selectors": 2, + "table_ids_column_idxes": [ + 10 + ], + "quotient_degree": 8, + "selectors_placement": { + "Fork": { + "left": { + "Fork": { + "left": { + "Fork": { + "left": { + "Fork": { + "left": { + "Fork": { + "left": { + "GateOnly": { + "gate_idx": 2, + "num_constants": 2, + "degree": 3, + "needs_selector": true, + "is_lookup": false + } + }, + "right": { + "Fork": { + "left": { + "GateOnly": { + "gate_idx": 7, + "num_constants": 0, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + }, + "right": { + "GateOnly": { + "gate_idx": 1, + "num_constants": 0, + "degree": 0, + "needs_selector": true, + "is_lookup": false + } + } + } + } + } + }, + "right": { + "GateOnly": { + "gate_idx": 6, + "num_constants": 0, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + } + } + }, + "right": { + "GateOnly": { + "gate_idx": 4, + "num_constants": 0, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + } + } + }, + "right": { + "GateOnly": { + "gate_idx": 5, + "num_constants": 1, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + } + } + }, + "right": { + "Fork": { + "left": { + "GateOnly": { + "gate_idx": 3, + "num_constants": 4, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + }, + "right": { + "GateOnly": { + "gate_idx": 0, + "num_constants": 8, + "degree": 1, + "needs_selector": true, + "is_lookup": false + } + } + } + } + } + }, + "fri_lde_factor": 2, + "cap_size": 16 + }, + "setup_merkle_tree_cap": [ + [ + 15012885272458350464, + 12918123785161914480, + 13671686572559106862, + 458420429559950553 + ], + [ + 3855596161956112429, + 9367986999640085982, + 9576686990164770909, + 15736630811802716592 + ], + [ + 4429424595585567228, + 1726575003907041811, + 11808623125777752326, + 7960090163308302001 + ], + [ + 16198073096358255703, + 1773566633554043329, + 15852741538281887312, + 3672365904403393548 + ], + [ + 5014302247141995239, + 15298901224361045295, + 17058410652708079000, + 2451098419087154466 + ], + [ + 1883879201519384194, + 16513689436046407106, + 18106823921911623646, + 12195558529156429070 + ], + [ + 3553190024094472044, + 16085740316966804610, + 7469059494943248345, + 8466978240947973162 + ], + [ + 15733255750285479223, + 10035744743646423118, + 12893682562633909811, + 17018145047346847928 + ], + [ + 4190189918857924629, + 11079126332194735217, + 81863766911265321, + 1252088896597638701 + ], + [ + 13713450655978854074, + 6658527377300991599, + 11379765760362527623, + 18157417093208935759 + ], + [ + 13291575128912167224, + 5612545196785048171, + 14736834588908638980, + 3368626854973932908 + ], + [ + 6550473513308471355, + 261602743346828260, + 3476562827380596578, + 16103482668860064473 + ], + [ + 3000784508673768350, + 1118466443868787057, + 13001376126891710198, + 5277667505560256643 + ], + [ + 1638204738185533106, + 2943638319874219165, + 37345818451115499, + 6602609125606041803 + ], + [ + 8835198552893947573, + 13366615065126505958, + 15913885131147312037, + 11776601604937573132 + ], + [ + 12125147286940007597, + 9198361601962582562, + 9157325123238861992, + 14770289666410955142 + ] + ] +} \ No newline at end of file diff --git a/prover/vk_setup_data_generator_server_fri/src/keystore.rs b/prover/vk_setup_data_generator_server_fri/src/keystore.rs index a684d2c121e0..dcbb7af96038 100644 --- a/prover/vk_setup_data_generator_server_fri/src/keystore.rs +++ b/prover/vk_setup_data_generator_server_fri/src/keystore.rs @@ -4,7 +4,7 @@ use anyhow::Context as _; use circuit_definitions::{ boojum::cs::implementations::setup::FinalizationHintsForProver, circuit_definitions::{ - aux_layer::ZkSyncSnarkWrapperVK, + aux_layer::{EIP4844VerificationKey, ZkSyncSnarkWrapperVK}, base_layer::ZkSyncBaseLayerVerificationKey, recursion_layer::{ZkSyncRecursionLayerStorageType, ZkSyncRecursionLayerVerificationKey}, }, @@ -85,16 +85,7 @@ impl Keystore { key: ProverServiceDataKey, service_data_type: ProverServiceDataType, ) -> String { - let name = match key.round { - AggregationRound::BasicCircuits => { - format!("basic_{}", key.circuit_id) - } - AggregationRound::LeafAggregation => { - format!("leaf_{}", key.circuit_id) - } - AggregationRound::NodeAggregation => "node".to_string(), - AggregationRound::Scheduler => "scheduler".to_string(), - }; + let name = key.name(); match service_data_type { ProverServiceDataType::VerificationKey => { format!("{}/verification_{}_key.json", self.basedir, name) @@ -163,6 +154,13 @@ impl Keystore { )) } + pub fn load_4844_verification_key(&self) -> anyhow::Result { + Self::load_json_from_file(self.get_file_path( + ProverServiceDataKey::eip4844(), + ProverServiceDataType::VerificationKey, + )) + } + pub fn save_base_layer_verification_key( &self, vk: ZkSyncBaseLayerVerificationKey, @@ -187,6 +185,15 @@ impl Keystore { Self::save_json_pretty(filepath, &vk) } + pub fn save_4844_verification_key(&self, vk: EIP4844VerificationKey) -> anyhow::Result<()> { + let filepath = self.get_file_path( + ProverServiceDataKey::eip4844(), + ProverServiceDataType::VerificationKey, + ); + tracing::info!("saving 4844 verification key to: {}", filepath); + Self::save_json_pretty(filepath, &vk) + } + /// /// Finalization hints /// @@ -325,6 +332,7 @@ impl Keystore { } pub fn save_keys_from_data_source(&self, source: &dyn SetupDataSource) -> anyhow::Result<()> { + // Base circuits for base_circuit_type in (BaseLayerCircuitType::VM as u8)..=(BaseLayerCircuitType::L1MessagesHasher as u8) { @@ -346,6 +354,7 @@ impl Keystore { self.save_finalization_hints(key, &hint) .context("save_finalization_hints()")?; } + // Leaf circuits for leaf_circuit_type in (ZkSyncRecursionLayerStorageType::LeafLayerCircuitForMainVM as u8) ..=(ZkSyncRecursionLayerStorageType::LeafLayerCircuitForL1MessagesHasher as u8) { @@ -369,6 +378,7 @@ impl Keystore { self.save_finalization_hints(key, &hint) .context("save_finalization_hints()")?; } + // Node self.save_recursive_layer_verification_key( source .get_recursion_layer_node_vk() @@ -390,6 +400,7 @@ impl Keystore { ) .context("save_finalization_hints()")?; + // Scheduler self.save_recursive_layer_verification_key( source .get_recursion_layer_vk(ZkSyncRecursionLayerStorageType::SchedulerCircuit as u8) @@ -414,6 +425,14 @@ impl Keystore { ) .context("save_finalization_hints()")?; + // 4844 + self.save_4844_verification_key( + source + .get_eip4844_vk() + .map_err(|err| anyhow::anyhow!("No vk exist for 4844 circuit: {err}"))?, + ) + .context("save_4844_verification_key()")?; + Ok(()) } } diff --git a/prover/vk_setup_data_generator_server_fri/src/main.rs b/prover/vk_setup_data_generator_server_fri/src/main.rs index ba3dce8a6177..44002476d5a1 100644 --- a/prover/vk_setup_data_generator_server_fri/src/main.rs +++ b/prover/vk_setup_data_generator_server_fri/src/main.rs @@ -8,7 +8,10 @@ use clap::{Parser, Subcommand}; use commitment_generator::read_and_update_contract_toml; use tracing::level_filters::LevelFilter; use zkevm_test_harness::{ - compute_setups::{generate_base_layer_vks_and_proofs, generate_recursive_layer_vks_and_proofs}, + compute_setups::{ + generate_base_layer_vks_and_proofs, generate_eip4844_vks, + generate_recursive_layer_vks_and_proofs, + }, data_source::{in_memory_data_source::InMemoryDataSource, SetupDataSource}, proof_wrapper_utils::{ check_trusted_setup_file_existace, get_wrapper_setup_and_vk_from_scheduler_vk, @@ -39,6 +42,10 @@ fn generate_vks(keystore: &Keystore) -> anyhow::Result<()> { tracing::info!("Generating verification keys for Recursive layer."); generate_recursive_layer_vks_and_proofs(&mut in_memory_source) .map_err(|err| anyhow::anyhow!("Failed generating recursive vk's: {err}"))?; + + generate_eip4844_vks(&mut in_memory_source) + .map_err(|err| anyhow::anyhow!("Failed generating 4844 vk's: {err}"))?; + tracing::info!("Saving keys & hints"); keystore.save_keys_from_data_source(&in_memory_source)?; From ce6c120c31b270739eecb102f6742237e6c9d004 Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Tue, 20 Feb 2024 22:39:06 +0200 Subject: [PATCH 009/106] feat(en): switch to tree light mode (#1152) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ EN runs tree in light mode. ## Why ❔ Full tree mode is no longer required for EN as commitment generation is moved to a new component. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- core/bin/external_node/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/bin/external_node/src/main.rs b/core/bin/external_node/src/main.rs index 8211e8596ab2..7845422ae213 100644 --- a/core/bin/external_node/src/main.rs +++ b/core/bin/external_node/src/main.rs @@ -228,7 +228,7 @@ async fn init_tasks( let metadata_calculator_config = MetadataCalculatorConfig { db_path: config.required.merkle_tree_path.clone(), - mode: MerkleTreeMode::Full, + mode: MerkleTreeMode::Lightweight, delay_interval: config.optional.metadata_calculator_delay(), max_l1_batches_per_iter: config.optional.max_l1_batches_per_tree_iter, multi_get_chunk_size: config.optional.merkle_tree_multi_get_chunk_size, From 975f54bca211b2b6de22a83d1dec120b31f4d39b Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Wed, 21 Feb 2024 08:17:26 +0100 Subject: [PATCH 010/106] feat: Adding ability to generate 4844 setup key and refactor (#1143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Refactored the code, to keep passing ProverServiceDataKey as a circuit identifier * Added support for 4844 setup key generation ## Why ❔ * 4844 circuit was recently added. --- prover/Cargo.lock | 6 +- prover/prover_fri/tests/basic_test.rs | 8 +- prover/prover_fri_types/src/lib.rs | 32 ++++- .../src/main.rs | 57 ++++----- .../src/setup_data_generator.rs | 121 +++++++----------- 5 files changed, 115 insertions(+), 109 deletions(-) diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 5154d57abfee..0ce09698ef4c 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -808,7 +808,7 @@ dependencies = [ [[package]] name = "circuit_definitions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#ce188bd36b9ea0d99a8cdb4da9beb91cd3f721c4" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#577f3d73f8c2e9c4cb8fe30f16672af66550af9f" dependencies = [ "crossbeam 0.8.4", "derivative", @@ -6721,7 +6721,7 @@ dependencies = [ [[package]] name = "zkevm_circuits" version = "1.4.1" -source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.4.1#873fe0fcf0bb8df6be0ae1938ce8469d6bf63ebd" +source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.4.1#3a973afb3cf2b50b7138c1af61cc6ac3d7d0189f" dependencies = [ "arrayvec 0.7.4", "bincode", @@ -6831,7 +6831,7 @@ dependencies = [ [[package]] name = "zkevm_test_harness" version = "1.4.1" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#ce188bd36b9ea0d99a8cdb4da9beb91cd3f721c4" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#577f3d73f8c2e9c4cb8fe30f16672af66550af9f" dependencies = [ "bincode", "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", diff --git a/prover/prover_fri/tests/basic_test.rs b/prover/prover_fri/tests/basic_test.rs index aad7651fb6dc..38654dcb37c3 100644 --- a/prover/prover_fri/tests/basic_test.rs +++ b/prover/prover_fri/tests/basic_test.rs @@ -57,9 +57,11 @@ async fn prover_and_assert_base_layer( CircuitWrapper::Recursive(_) => anyhow::bail!("Expected base layer circuit"), }; let keystore = Keystore::default(); - let circuit_setup_data = - generate_setup_data_common(&keystore, true, circuit.numeric_circuit_type()) - .context("generate_cpu_base_layers_setup_data()")?; + let circuit_setup_data = generate_setup_data_common( + &keystore, + ProverServiceDataKey::new_basic(circuit.numeric_circuit_type()), + ) + .context("generate_cpu_base_layers_setup_data()")?; let setup_data = Arc::new(circuit_setup_data.into()); let setup_key = ProverServiceDataKey::new(circuit_id, aggregation_round); let prover_job = ProverJob::new(block_number, expected_proof_id, circuit_wrapper, setup_key); diff --git a/prover/prover_fri_types/src/lib.rs b/prover/prover_fri_types/src/lib.rs index 9d9c6c1a6ee6..56adb330f574 100644 --- a/prover/prover_fri_types/src/lib.rs +++ b/prover/prover_fri_types/src/lib.rs @@ -10,7 +10,9 @@ use circuit_definitions::{ ZkSyncRecursionLayerProof, ZkSyncRecursionLayerStorageType, ZkSyncRecursiveLayerCircuit, }, }, - zkevm_circuits::scheduler::block_header::BlockAuxilaryOutputWitness, + zkevm_circuits::scheduler::{ + aux::BaseLayerCircuitType, block_header::BlockAuxilaryOutputWitness, + }, ZkSyncDefaultRoundFunction, }; use zksync_object_store::{serialize_using_bincode, Bucket, StoredObject}; @@ -138,6 +140,30 @@ impl ProverServiceDataKey { round: get_round_for_recursive_circuit_type(circuit_id), } } + pub fn new_basic(circuit_id: u8) -> Self { + Self { + circuit_id, + round: AggregationRound::BasicCircuits, + } + } + + pub fn all_boojum() -> Vec { + let mut results = vec![]; + for numeric_circuit in + BaseLayerCircuitType::VM as u8..=BaseLayerCircuitType::L1MessagesHasher as u8 + { + results.push(ProverServiceDataKey::new_basic(numeric_circuit)) + } + for numeric_circuit in ZkSyncRecursionLayerStorageType::SchedulerCircuit as u8 + ..=ZkSyncRecursionLayerStorageType::LeafLayerCircuitForL1MessagesHasher as u8 + { + results.push(ProverServiceDataKey::new_recursive(numeric_circuit)) + } + results.push(ProverServiceDataKey::eip4844()); + // Don't include snark, as it uses the old proving system. + + results + } /// Data key for snark wrapper. pub fn snark() -> Self { @@ -163,6 +189,10 @@ impl ProverServiceDataKey { && self.round == AggregationRound::BasicCircuits } + pub fn is_base_layer(&self) -> bool { + self.round == AggregationRound::BasicCircuits && !self.is_eip4844() + } + pub fn name(&self) -> String { if self.is_eip4844() { return "eip4844".to_string(); diff --git a/prover/vk_setup_data_generator_server_fri/src/main.rs b/prover/vk_setup_data_generator_server_fri/src/main.rs index 44002476d5a1..dadbd4b72f9e 100644 --- a/prover/vk_setup_data_generator_server_fri/src/main.rs +++ b/prover/vk_setup_data_generator_server_fri/src/main.rs @@ -18,7 +18,10 @@ use zkevm_test_harness::{ WrapperConfig, }, }; -use zksync_prover_fri_types::circuit_definitions::circuit_definitions::recursion_layer::ZkSyncRecursionLayerStorageType; +use zksync_prover_fri_types::{ + circuit_definitions::circuit_definitions::recursion_layer::ZkSyncRecursionLayerStorageType, + ProverServiceDataKey, +}; use zksync_vk_setup_data_server_fri::{ keystore::Keystore, setup_data_generator::{CPUSetupDataGenerator, GPUSetupDataGenerator, SetupDataGenerator}, @@ -85,6 +88,8 @@ enum CircuitSelector { Recursive, /// Select circuits from basic group. Basic, + /// EIP 4844 circuit + Eip4844, } #[derive(Debug, Parser)] @@ -163,39 +168,31 @@ fn generate_setup_keys( generator: &dyn SetupDataGenerator, options: &GeneratorOptions, ) -> anyhow::Result<()> { - match options.circuits_type { + let circuit_type = match options.circuits_type { CircuitSelector::All => { let digests = generator.generate_all(options.dry_run)?; tracing::info!("Setup keys md5(s):"); - print_stats(digests) - } - CircuitSelector::Recursive => { - let digest = generator - .generate_and_write_setup_data( - false, - options - .numeric_circuit - .expect("--numeric-circuit must be provided"), - options.dry_run, - ) - .context("generate_setup_data()")?; - tracing::info!("digest: {:?}", digest); - Ok(()) - } - CircuitSelector::Basic => { - let digest = generator - .generate_and_write_setup_data( - true, - options - .numeric_circuit - .expect("--numeric-circuit must be provided"), - options.dry_run, - ) - .context("generate_setup_data()")?; - tracing::info!("digest: {:?}", digest); - Ok(()) + print_stats(digests)?; + return Ok(()); } - } + CircuitSelector::Recursive => ProverServiceDataKey::new_recursive( + options + .numeric_circuit + .expect("--numeric-circuit must be provided"), + ), + CircuitSelector::Basic => ProverServiceDataKey::new_basic( + options + .numeric_circuit + .expect("--numeric-circuit must be provided"), + ), + CircuitSelector::Eip4844 => ProverServiceDataKey::eip4844(), + }; + + let digest = generator + .generate_and_write_setup_data(circuit_type, options.dry_run) + .context("generate_setup_data()")?; + tracing::info!("digest: {:?}", digest); + Ok(()) } fn main() -> anyhow::Result<()> { diff --git a/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs b/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs index 2e73ec8cf652..371bfbe0327b 100644 --- a/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs +++ b/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs @@ -4,16 +4,13 @@ use std::collections::HashMap; use anyhow::Context as _; -use circuit_definitions::{ - circuit_definitions::recursion_layer::ZkSyncRecursionLayerStorageType, - zkevm_circuits::scheduler::aux::BaseLayerCircuitType, -}; use zkevm_test_harness::{ - compute_setups::{generate_circuit_setup_data, CircuitSetupData}, + compute_setups::{ + generate_circuit_setup_data, generate_circuit_setup_data_4844, CircuitSetupData, + }, data_source::SetupDataSource, }; use zksync_prover_fri_types::ProverServiceDataKey; -use zksync_types::basic_fri_types::AggregationRound; #[cfg(feature = "gpu")] use { crate::GpuProverSetupData, shivini::cs::setup::GpuSetup, shivini::ProverContext, @@ -26,40 +23,51 @@ use crate::{keystore::Keystore, GoldilocksProverSetupData}; /// It also does a final sanity check to make sure that verification keys didn't change. pub fn generate_setup_data_common( keystore: &Keystore, - is_base_layer: bool, - circuit_type: u8, + circuit: ProverServiceDataKey, ) -> anyhow::Result { let mut data_source = keystore.load_keys_to_data_source()?; - let circuit_setup_data = - generate_circuit_setup_data(is_base_layer, circuit_type, &mut data_source).unwrap(); + let circuit_setup_data = if circuit.is_eip4844() { + generate_circuit_setup_data_4844().unwrap() + } else { + generate_circuit_setup_data( + circuit.is_base_layer(), + circuit.circuit_id, + &mut data_source, + ) + .unwrap() + }; - let (finalization, vk) = if is_base_layer { + let (finalization, vk) = if circuit.is_eip4844() { + (None, data_source.get_eip4844_vk().unwrap()) + } else if circuit.is_base_layer() { ( - keystore.load_finalization_hints(ProverServiceDataKey::new( - circuit_type, - AggregationRound::BasicCircuits, - ))?, + Some(keystore.load_finalization_hints(circuit.clone())?), data_source - .get_base_layer_vk(circuit_type) + .get_base_layer_vk(circuit.circuit_id) .unwrap() .into_inner(), ) } else { ( - keystore.load_finalization_hints(ProverServiceDataKey::new_recursive(circuit_type))?, + Some(keystore.load_finalization_hints(circuit.clone())?), data_source - .get_recursion_layer_vk(circuit_type) + .get_recursion_layer_vk(circuit.circuit_id) .unwrap() .into_inner(), ) }; // Sanity check to make sure that generated setup data is matching. - if finalization != circuit_setup_data.finalization_hint { - anyhow::bail!("finalization hint mismatch for circuit: {circuit_type}"); + if let Some(finalization) = finalization { + if finalization != circuit_setup_data.finalization_hint { + anyhow::bail!( + "finalization hint mismatch for circuit: {:?}", + circuit.name() + ); + } } if vk != circuit_setup_data.vk { - anyhow::bail!("vk mismatch for circuit: {circuit_type}"); + anyhow::bail!("vk mismatch for circuit: {:?}", circuit.name()); } Ok(circuit_setup_data) } @@ -67,11 +75,7 @@ pub fn generate_setup_data_common( /// Trait to cover GPU and CPU setup data generation. pub trait SetupDataGenerator { /// Generates the setup keys. - fn generate_setup_data( - &self, - is_base_layer: bool, - numeric_circuit: u8, - ) -> anyhow::Result>; + fn generate_setup_data(&self, circuit: ProverServiceDataKey) -> anyhow::Result>; fn keystore(&self) -> &Keystore; @@ -79,23 +83,15 @@ pub trait SetupDataGenerator { /// Returns the md5 check sum of the stored file. fn generate_and_write_setup_data( &self, - is_base_layer: bool, - numeric_circuit: u8, + circuit: ProverServiceDataKey, dry_run: bool, ) -> anyhow::Result { - let serialized = self.generate_setup_data(is_base_layer, numeric_circuit)?; + let serialized = self.generate_setup_data(circuit.clone())?; let digest = md5::compute(&serialized); if !dry_run { self.keystore() - .save_setup_data_for_circuit_type( - if is_base_layer { - ProverServiceDataKey::new(numeric_circuit, AggregationRound::BasicCircuits) - } else { - ProverServiceDataKey::new_recursive(numeric_circuit) - }, - &serialized, - ) + .save_setup_data_for_circuit_type(circuit, &serialized) .context("save_setup_data()")?; } else { tracing::warn!("Dry run - not writing the key"); @@ -103,27 +99,18 @@ pub trait SetupDataGenerator { Ok(format!("{:?}", digest)) } + /// Generate all setup keys for boojum circuits. fn generate_all(&self, dry_run: bool) -> anyhow::Result> { - let mut result = HashMap::new(); - - for numeric_circuit in - BaseLayerCircuitType::VM as u8..=BaseLayerCircuitType::L1MessagesHasher as u8 - { - let digest = self - .generate_and_write_setup_data(true, numeric_circuit, dry_run) - .context(format!("base layer, circuit {:?}", numeric_circuit))?; - result.insert(format!("base_{}", numeric_circuit), digest); - } - - for numeric_circuit in ZkSyncRecursionLayerStorageType::SchedulerCircuit as u8 - ..=ZkSyncRecursionLayerStorageType::LeafLayerCircuitForL1MessagesHasher as u8 - { - let digest = self - .generate_and_write_setup_data(false, numeric_circuit, dry_run) - .context(format!("recursive layer, circuit {:?}", numeric_circuit))?; - result.insert(format!("recursive_{}", numeric_circuit), digest); - } - Ok(result) + Ok(ProverServiceDataKey::all_boojum() + .iter() + .map(|circuit| { + let digest = self + .generate_and_write_setup_data(circuit.clone(), dry_run) + .context(circuit.name()) + .unwrap(); + (circuit.name(), digest) + }) + .collect()) } } @@ -132,13 +119,8 @@ pub struct CPUSetupDataGenerator { } impl SetupDataGenerator for CPUSetupDataGenerator { - fn generate_setup_data( - &self, - is_base_layer: bool, - numeric_circuit: u8, - ) -> anyhow::Result> { - let circuit_setup_data = - generate_setup_data_common(&self.keystore, is_base_layer, numeric_circuit)?; + fn generate_setup_data(&self, circuit: ProverServiceDataKey) -> anyhow::Result> { + let circuit_setup_data = generate_setup_data_common(&self.keystore, circuit)?; let prover_setup_data: GoldilocksProverSetupData = circuit_setup_data.into(); @@ -155,22 +137,17 @@ pub struct GPUSetupDataGenerator { } impl SetupDataGenerator for GPUSetupDataGenerator { - fn generate_setup_data( - &self, - is_base_layer: bool, - numeric_circuit: u8, - ) -> anyhow::Result> { + fn generate_setup_data(&self, circuit: ProverServiceDataKey) -> anyhow::Result> { #[cfg(not(feature = "gpu"))] { - let _ = (is_base_layer, numeric_circuit); + let _ = circuit; anyhow::bail!("Must compile with --gpu feature to use this option."); } #[cfg(feature = "gpu")] { let _context = ProverContext::create().context("failed initializing gpu prover context")?; - let circuit_setup_data = - generate_setup_data_common(&self.keystore, is_base_layer, numeric_circuit)?; + let circuit_setup_data = generate_setup_data_common(&self.keystore, circuit)?; let worker = Worker::new(); let gpu_setup_data = GpuSetup::from_setup_and_hints( From f983e803c7c0f5c41f8beaabc820676be84d7825 Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Wed, 21 Feb 2024 09:36:37 +0200 Subject: [PATCH 011/106] feat(en): Start health checks early into EN lifecycle (#1146) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - Implements shared thread-safe container for health checks, `AppHealthCheck`. - Refactors EN initialization to start the healthcheck server early into the node lifecycle. - Adds a healthcheck for snapshot recovery. - Uses healthchecks in the snapshot recovery integration test. ## Why ❔ This increases EN observability. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [x] Tests for the changes have been added / updated. - [x] Documentation comments have been added / updated. - [x] Code has been formatted via `zk fmt` and `zk lint`. - [x] Spellcheck has been run via `zk spellcheck`. - [x] Linkcheck has been run via `zk linkcheck`. --- Cargo.lock | 3 +- core/bin/external_node/src/init.rs | 24 +-- core/bin/external_node/src/main.rs | 109 +++++++------- core/lib/health_check/src/lib.rs | 77 +++++++++- core/lib/snapshots_applier/Cargo.toml | 3 +- core/lib/snapshots_applier/src/lib.rs | 131 +++++++++++------ core/lib/snapshots_applier/src/tests/mod.rs | 27 ++-- .../zksync_core/src/api_server/healthcheck.rs | 40 ++--- .../src/api_server/tx_sender/mod.rs | 5 +- .../src/api_server/tx_sender/proxy.rs | 5 +- .../src/l1_gas_price/main_node_fetcher.rs | 14 +- core/lib/zksync_core/src/lib.rs | 29 ++-- .../lib/zksync_core/src/reorg_detector/mod.rs | 10 +- .../sync_layer/batch_status_updater/mod.rs | 13 +- .../layers/healtcheck_server.rs | 28 ++-- .../layers/metadata_calculator.rs | 13 +- .../layers/prometheus_exporter.rs | 11 +- .../implementations/resources/healthcheck.rs | 32 +--- .../tests/snapshot-recovery.test.ts | 137 ++++++++++++++---- etc/env/ext-node.toml | 1 + 20 files changed, 408 insertions(+), 304 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff9991960eb0..e4c25ee5b5e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8914,14 +8914,15 @@ name = "zksync_snapshots_applier" version = "0.1.0" dependencies = [ "anyhow", - "assert_matches", "async-trait", + "serde", "test-casing", "thiserror", "tokio", "tracing", "vise", "zksync_dal", + "zksync_health_check", "zksync_object_store", "zksync_types", "zksync_utils", diff --git a/core/bin/external_node/src/init.rs b/core/bin/external_node/src/init.rs index c0d158025992..e8339f5afa39 100644 --- a/core/bin/external_node/src/init.rs +++ b/core/bin/external_node/src/init.rs @@ -4,8 +4,9 @@ use anyhow::Context as _; use zksync_basic_types::{L1BatchNumber, L2ChainId}; use zksync_core::sync_layer::genesis::perform_genesis_if_needed; use zksync_dal::ConnectionPool; +use zksync_health_check::AppHealthCheck; use zksync_object_store::ObjectStoreFactory; -use zksync_snapshots_applier::{SnapshotsApplierConfig, SnapshotsApplierOutcome}; +use zksync_snapshots_applier::SnapshotsApplierConfig; use zksync_web3_decl::jsonrpsee::http_client::HttpClient; use crate::config::read_snapshots_recovery_config; @@ -21,6 +22,7 @@ enum InitDecision { pub(crate) async fn ensure_storage_initialized( pool: &ConnectionPool, main_node_client: &HttpClient, + app_health: &AppHealthCheck, l2_chain_id: L2ChainId, consider_snapshot_recovery: bool, ) -> anyhow::Result<()> { @@ -83,24 +85,14 @@ pub(crate) async fn ensure_storage_initialized( let blob_store = ObjectStoreFactory::new(recovery_config.snapshots_object_store) .create_store() .await; - let outcome = SnapshotsApplierConfig::default() + + let config = SnapshotsApplierConfig::default(); + app_health.insert_component(config.health_check()); + config .run(pool, main_node_client, &blob_store) .await .context("snapshot recovery failed")?; - match outcome { - SnapshotsApplierOutcome::Ok => { - tracing::info!("Snapshot recovery is complete"); - } - SnapshotsApplierOutcome::NoSnapshotsOnMainNode => { - anyhow::bail!("No snapshots on main node; snapshot recovery is impossible"); - } - SnapshotsApplierOutcome::InitializedWithoutSnapshot => { - anyhow::bail!( - "Node contains a non-genesis L1 batch, but no genesis; snapshot recovery is unsafe. \ - This should never occur unless the node DB was manually tampered with" - ); - } - } + tracing::info!("Snapshot recovery is complete"); } } Ok(()) diff --git a/core/bin/external_node/src/main.rs b/core/bin/external_node/src/main.rs index 7845422ae213..b36e62e16126 100644 --- a/core/bin/external_node/src/main.rs +++ b/core/bin/external_node/src/main.rs @@ -34,10 +34,11 @@ use zksync_core::{ }, }; use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; -use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; +use zksync_health_check::{AppHealthCheck, HealthStatus, ReactiveHealthCheck}; use zksync_state::PostgresStorageCaches; use zksync_storage::RocksDB; use zksync_utils::wait_for_tasks::wait_for_tasks; +use zksync_web3_decl::jsonrpsee::http_client::HttpClient; use crate::{ config::{observability::observability_config_from_env, ExternalNodeConfig}, @@ -111,11 +112,11 @@ async fn build_state_keeper( async fn init_tasks( config: &ExternalNodeConfig, connection_pool: ConnectionPool, + main_node_client: HttpClient, + task_handles: &mut Vec>>, + app_health: &AppHealthCheck, stop_receiver: watch::Receiver, -) -> anyhow::Result<( - Vec>>, - Vec>, -)> { +) -> anyhow::Result<()> { let release_manifest: serde_json::Value = serde_json::from_str(RELEASE_MANIFEST) .expect("release manifest is a valid json document; qed"); let release_manifest_version = release_manifest["core"].as_str().expect( @@ -124,19 +125,13 @@ async fn init_tasks( let version = semver::Version::parse(release_manifest_version) .expect("version in manifest is a correct semver format; qed"); - let main_node_url = config - .required - .main_node_url() - .expect("Main node URL is incorrect"); - let mut healthchecks: Vec> = Vec::new(); // Create components. - let fee_params_fetcher = Arc::new(MainNodeFeeParamsFetcher::new(&main_node_url)); + let fee_params_fetcher = Arc::new(MainNodeFeeParamsFetcher::new(main_node_client.clone())); let sync_state = SyncState::default(); - healthchecks.push(Box::new(sync_state.clone())); + app_health.insert_custom_component(Arc::new(sync_state.clone())); let (action_queue_sender, action_queue) = ActionQueue::new(); - let mut task_handles = vec![]; let (miniblock_sealer, miniblock_sealer_handle) = MiniblockSealer::new( connection_pool.clone(), config.optional.miniblock_seal_queue_capacity, @@ -173,22 +168,15 @@ async fn init_tasks( ) .await?; - let main_node_client = ::json_rpc(&main_node_url) - .context("Failed creating JSON-RPC client for main node")?; - healthchecks.push(Box::new(MainNodeHealthCheck::from( - main_node_client.clone(), - ))); let singleton_pool_builder = ConnectionPool::singleton(&config.postgres.database_url); let fetcher_handle = if let Some(cfg) = config.consensus.clone() { let pool = connection_pool.clone(); let mut stop_receiver = stop_receiver.clone(); let sync_state = sync_state.clone(); + let main_node_client = main_node_client.clone(); - #[allow(clippy::redundant_locals)] tokio::spawn(async move { - let sync_state = sync_state; - let main_node_client = main_node_client; scope::run!(&ctx::root(), |ctx, s| async { s.spawn_bg(async { let res = cfg.run(ctx, pool, action_queue_sender).await; @@ -216,7 +204,7 @@ async fn init_tasks( let mut storage = pool.access_storage_tagged("sync_layer").await?; let fetcher = MainNodeFetcher::new( &mut storage, - Box::new(main_node_client), + Box::new(main_node_client.clone()), action_queue_sender, sync_state.clone(), stop_receiver.clone(), @@ -239,7 +227,7 @@ async fn init_tasks( let metadata_calculator = MetadataCalculator::new(metadata_calculator_config, None) .await .context("failed initializing metadata calculator")?; - healthchecks.push(Box::new(metadata_calculator.tree_health_check())); + app_health.insert_component(metadata_calculator.tree_health_check()); let consistency_checker = ConsistencyChecker::new( &config @@ -252,18 +240,17 @@ async fn init_tasks( .await .context("failed to build connection pool for ConsistencyChecker")?, ); - healthchecks.push(Box::new(consistency_checker.health_check().clone())); + app_health.insert_component(consistency_checker.health_check().clone()); let consistency_checker_handle = tokio::spawn(consistency_checker.run(stop_receiver.clone())); let batch_status_updater = BatchStatusUpdater::new( - &main_node_url, + main_node_client.clone(), singleton_pool_builder .build() .await .context("failed to build a connection pool for BatchStatusUpdater")?, - ) - .context("failed initializing batch status updater")?; - healthchecks.push(Box::new(batch_status_updater.health_check())); + ); + app_health.insert_component(batch_status_updater.health_check()); // Run the components. let tree_stop_receiver = stop_receiver.clone(); @@ -278,7 +265,7 @@ async fn init_tasks( .await .context("failed to build a commitment_generator_pool")?; let commitment_generator = CommitmentGenerator::new(commitment_generator_pool); - healthchecks.push(Box::new(commitment_generator.health_check())); + app_health.insert_component(commitment_generator.health_check()); let commitment_generator_handle = tokio::spawn(commitment_generator.run(stop_receiver.clone())); let updater_handle = task::spawn(batch_status_updater.run(stop_receiver.clone())); @@ -292,7 +279,7 @@ async fn init_tasks( let tx_sender_builder = TxSenderBuilder::new(config.clone().into(), connection_pool.clone()) .with_main_connection_pool(connection_pool.clone()) - .with_tx_proxy(&main_node_url); + .with_tx_proxy(main_node_client); if config.optional.transactions_per_sec_limit.is_some() { tracing::warn!("`transactions_per_sec_limit` option is deprecated and ignored"); @@ -352,14 +339,13 @@ async fn init_tasks( .await .context("Failed initializing WS JSON-RPC server")?; - healthchecks.push(Box::new(ws_server_handles.health_check)); - healthchecks.push(Box::new(http_server_handles.health_check)); - healthchecks.push(Box::new(ConnectionPoolHealthCheck::new(connection_pool))); + app_health.insert_component(ws_server_handles.health_check); + app_health.insert_component(http_server_handles.health_check); if let Some(port) = config.optional.prometheus_port { let (prometheus_health_check, prometheus_health_updater) = ReactiveHealthCheck::new("prometheus_exporter"); - healthchecks.push(Box::new(prometheus_health_check)); + app_health.insert_component(prometheus_health_check); task_handles.push(tokio::spawn(async move { prometheus_health_updater.update(HealthStatus::Ready.into()); let result = PrometheusExporterConfig::pull(port) @@ -384,7 +370,7 @@ async fn init_tasks( commitment_generator_handle, ]); - Ok((task_handles, healthchecks)) + Ok(()) } async fn shutdown_components( @@ -462,13 +448,6 @@ async fn main() -> anyhow::Result<()> { Some(config::read_consensus_config().context("read_consensus_config()")?); } - let main_node_url = config - .required - .main_node_url() - .context("Main node URL is incorrect")?; - let main_node_client = ::json_rpc(&main_node_url) - .context("Failed creating JSON-RPC client for main node")?; - if let Some(threshold) = config.optional.slow_query_threshold() { ConnectionPool::global_config().set_slow_query_threshold(threshold)?; } @@ -518,29 +497,53 @@ async fn main() -> anyhow::Result<()> { let sigint_receiver = setup_sigint_handler(); tracing::warn!("The external node is in the alpha phase, and should be used with caution."); tracing::info!("Started the external node"); - tracing::info!("Main node URL is: {}", main_node_url); + let main_node_url = config + .required + .main_node_url() + .expect("Main node URL is incorrect"); + tracing::info!("Main node URL is: {main_node_url}"); + + let main_node_client = ::json_rpc(&main_node_url) + .context("Failed creating JSON-RPC client for main node")?; + let app_health = Arc::new(AppHealthCheck::default()); + app_health.insert_custom_component(Arc::new(MainNodeHealthCheck::from( + main_node_client.clone(), + ))); + app_health.insert_custom_component(Arc::new(ConnectionPoolHealthCheck::new( + connection_pool.clone(), + ))); + + // Start the health check server early into the node lifecycle so that its health can be monitored from the very start. + let healthcheck_handle = HealthCheckHandle::spawn_server( + ([0, 0, 0, 0], config.required.healthcheck_port).into(), + app_health.clone(), + ); // Make sure that the node storage is initialized either via genesis or snapshot recovery. ensure_storage_initialized( &connection_pool, &main_node_client, + &app_health, config.remote.l2_chain_id, opt.enable_snapshots_recovery, ) .await?; let (stop_sender, stop_receiver) = watch::channel(false); - let (task_handles, mut healthchecks) = - init_tasks(&config, connection_pool.clone(), stop_receiver.clone()) - .await - .context("init_tasks")?; + let mut task_handles = vec![]; + init_tasks( + &config, + connection_pool.clone(), + main_node_client.clone(), + &mut task_handles, + &app_health, + stop_receiver.clone(), + ) + .await + .context("init_tasks")?; - let reorg_detector = ReorgDetector::new(&main_node_url, connection_pool.clone()); - healthchecks.push(Box::new(reorg_detector.health_check().clone())); - let healthcheck_handle = HealthCheckHandle::spawn_server( - ([0, 0, 0, 0], config.required.healthcheck_port).into(), - healthchecks, - ); + let reorg_detector = ReorgDetector::new(main_node_client, connection_pool.clone()); + app_health.insert_component(reorg_detector.health_check().clone()); let mut reorg_detector_handle = tokio::spawn(reorg_detector.run(stop_receiver)).fuse(); let mut reorg_detector_result = None; diff --git a/core/lib/health_check/src/lib.rs b/core/lib/health_check/src/lib.rs index d5a66916a269..c85a1b53bd25 100644 --- a/core/lib/health_check/src/lib.rs +++ b/core/lib/health_check/src/lib.rs @@ -1,4 +1,10 @@ -use std::{collections::HashMap, thread, time::Duration}; +use std::{ + collections::HashMap, + fmt, + sync::{Arc, Mutex}, + thread, + time::Duration, +}; // Public re-export for other crates to be able to implement the interface. pub use async_trait::async_trait; @@ -73,6 +79,37 @@ impl From for Health { } } +/// Application health check aggregating health from multiple components. +#[derive(Debug, Default)] +pub struct AppHealthCheck(Mutex>>); + +impl AppHealthCheck { + /// Inserts health check for a component. + pub fn insert_component(&self, health_check: ReactiveHealthCheck) { + self.insert_custom_component(Arc::new(health_check)); + } + + /// Inserts a custom health check for a component. + pub fn insert_custom_component(&self, health_check: Arc) { + let health_check_name = health_check.name(); + let mut guard = self.0.lock().expect("`AppHealthCheck` is poisoned"); + if guard.iter().any(|check| check.name() == health_check_name) { + tracing::warn!( + "Health check with name `{health_check_name}` is redefined; only the last mention \ + will be present in `/health` endpoint output" + ); + } + guard.push(health_check); + } + + /// Checks the overall application health. This will query all component checks concurrently. + pub async fn check_health(&self) -> AppHealth { + // Clone checks so that we don't hold a lock for them across a wait point. + let health_checks = self.0.lock().expect("`AppHealthCheck` is poisoned").clone(); + AppHealth::new(&health_checks).await + } +} + /// Health information for an application consisting of multiple components. #[derive(Debug, Serialize)] pub struct AppHealth { @@ -83,7 +120,7 @@ pub struct AppHealth { impl AppHealth { /// Aggregates health info from the provided checks. - pub async fn new>(health_checks: &[T]) -> Self { + async fn new(health_checks: &[Arc]) -> Self { let check_futures = health_checks .iter() .map(|check| Self::check_health_with_time_limit(check.as_ref())); @@ -146,6 +183,15 @@ pub trait CheckHealth: Send + Sync + 'static { async fn check_health(&self) -> Health; } +impl fmt::Debug for dyn CheckHealth { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("CheckHealth") + .field("name", &self.name()) + .finish() + } +} + /// Basic implementation of [`CheckHealth`] trait that can be updated using a matching [`HealthUpdater`]. #[derive(Debug, Clone)] pub struct ReactiveHealthCheck { @@ -164,6 +210,7 @@ impl ReactiveHealthCheck { }; let updater = HealthUpdater { name, + should_track_drop: true, health_sender, }; (this, updater) @@ -184,10 +231,11 @@ impl CheckHealth for ReactiveHealthCheck { /// Updater for [`ReactiveHealthCheck`]. Can be created using [`ReactiveHealthCheck::new()`]. /// /// On drop, will automatically update status to [`HealthStatus::ShutDown`], or to [`HealthStatus::Panicked`] -/// if the dropping thread is panicking. +/// if the dropping thread is panicking, unless the drop is performed using [`Self::freeze()`]. #[derive(Debug)] pub struct HealthUpdater { name: &'static str, + should_track_drop: bool, health_sender: watch::Sender, } @@ -209,6 +257,11 @@ impl HealthUpdater { false } + /// Closes this updater so that the corresponding health check can no longer be updated, not even if the updater is dropped. + pub fn freeze(mut self) { + self.should_track_drop = false; + } + /// Creates a [`ReactiveHealthCheck`] attached to this updater. This allows not retaining the initial health check /// returned by [`ReactiveHealthCheck::new()`]. pub fn subscribe(&self) -> ReactiveHealthCheck { @@ -221,6 +274,10 @@ impl HealthUpdater { impl Drop for HealthUpdater { fn drop(&mut self) { + if !self.should_track_drop { + return; + } + let terminal_health = if thread::panicking() { HealthStatus::Panicked.into() } else { @@ -258,6 +315,18 @@ mod tests { ); } + #[tokio::test] + async fn updating_health_status_after_freeze() { + let (health_check, health_updater) = ReactiveHealthCheck::new("test"); + health_updater.update(HealthStatus::Ready.into()); + health_updater.freeze(); + + assert_matches!( + health_check.check_health().await.status(), + HealthStatus::Ready + ); + } + #[tokio::test] async fn updating_health_status_after_panic() { let (health_check, health_updater) = ReactiveHealthCheck::new("test"); @@ -301,7 +370,7 @@ mod tests { async fn aggregating_health_checks() { let (first_check, first_updater) = ReactiveHealthCheck::new("first"); let (second_check, second_updater) = ReactiveHealthCheck::new("second"); - let checks: Vec> = vec![Box::new(first_check), Box::new(second_check)]; + let checks: Vec> = vec![Arc::new(first_check), Arc::new(second_check)]; let app_health = AppHealth::new(&checks).await; assert!(!app_health.is_healthy()); diff --git a/core/lib/snapshots_applier/Cargo.toml b/core/lib/snapshots_applier/Cargo.toml index 82fc9a5557a3..533858b88fc2 100644 --- a/core/lib/snapshots_applier/Cargo.toml +++ b/core/lib/snapshots_applier/Cargo.toml @@ -11,6 +11,7 @@ categories = ["cryptography"] [dependencies] zksync_dal = { path = "../../lib/dal" } +zksync_health_check = { path = "../../lib/health_check" } zksync_types = { path = "../../lib/types" } zksync_object_store = { path = "../../lib/object_store" } zksync_web3_decl = { path = "../../lib/web3_decl" } @@ -23,7 +24,7 @@ async-trait = "0.1" tokio = { version = "1", features = ["time"] } tracing = "0.1" thiserror = "1.0" +serde = { version = "1.0.189", features = ["derive"] } [dev-dependencies] -assert_matches = "1.5.0" test-casing = "0.1.2" diff --git a/core/lib/snapshots_applier/src/lib.rs b/core/lib/snapshots_applier/src/lib.rs index b503d3b39112..748824dba408 100644 --- a/core/lib/snapshots_applier/src/lib.rs +++ b/core/lib/snapshots_applier/src/lib.rs @@ -4,8 +4,10 @@ use std::{collections::HashMap, fmt, time::Duration}; use anyhow::Context as _; use async_trait::async_trait; +use serde::Serialize; use tokio::sync::Semaphore; use zksync_dal::{ConnectionPool, SqlxError, StorageProcessor}; +use zksync_health_check::{Health, HealthStatus, HealthUpdater, ReactiveHealthCheck}; use zksync_object_store::{ObjectStore, ObjectStoreError}; use zksync_types::{ api::en::SyncBlock, @@ -15,7 +17,7 @@ use zksync_types::{ }, tokens::TokenInfo, web3::futures, - MiniblockNumber, H256, + L1BatchNumber, MiniblockNumber, H256, }; use zksync_utils::bytecode::hash_bytecode; use zksync_web3_decl::{ @@ -30,11 +32,18 @@ mod metrics; #[cfg(test)] mod tests; +#[derive(Debug, Serialize)] +struct SnapshotsApplierHealthDetails { + snapshot_miniblock: MiniblockNumber, + snapshot_l1_batch: L1BatchNumber, + factory_deps_recovered: bool, + storage_logs_chunk_count: usize, + storage_logs_chunks_left_to_process: usize, + tokens_recovered: bool, +} + #[derive(Debug, thiserror::Error)] enum SnapshotsApplierError { - // Not really an error, just an early return from snapshot application logic. - #[error("snapshot application returned early: {0:?}")] - EarlyReturn(SnapshotsApplierOutcome), #[error(transparent)] Fatal(#[from] anyhow::Error), #[error(transparent)] @@ -68,12 +77,6 @@ impl SnapshotsApplierError { } } -impl From for SnapshotsApplierError { - fn from(outcome: SnapshotsApplierOutcome) -> Self { - Self::EarlyReturn(outcome) - } -} - impl From for SnapshotsApplierError { fn from(err: EnrichedClientError) -> Self { match err.as_ref() { @@ -85,18 +88,6 @@ impl From for SnapshotsApplierError { } } -/// Non-erroneous outcomes of the snapshot application. -#[must_use = "Depending on app, `NoSnapshotsOnMainNode` may be considered an error"] -#[derive(Debug)] -pub enum SnapshotsApplierOutcome { - /// The node DB was successfully recovered from a snapshot. - Ok, - /// Main node does not have any ready snapshots. - NoSnapshotsOnMainNode, - /// The node was initialized without a snapshot. Detected by the presence of L1 batches in Postgres. - InitializedWithoutSnapshot, -} - /// Main node API used by the [`SnapshotsApplier`]. #[async_trait] pub trait SnapshotsApplierMainNodeClient: fmt::Debug + Send + Sync { @@ -156,6 +147,7 @@ pub struct SnapshotsApplierConfig { pub retry_count: usize, pub initial_retry_backoff: Duration, pub retry_backoff_multiplier: f32, + health_updater: HealthUpdater, } impl Default for SnapshotsApplierConfig { @@ -164,6 +156,7 @@ impl Default for SnapshotsApplierConfig { retry_count: 5, initial_retry_backoff: Duration::from_secs(2), retry_backoff_multiplier: 2.0, + health_updater: ReactiveHealthCheck::new("snapshot_recovery").1, } } } @@ -177,30 +170,48 @@ impl SnapshotsApplierConfig { } } + /// Returns the health check for snapshot recovery. + pub fn health_check(&self) -> ReactiveHealthCheck { + self.health_updater.subscribe() + } + /// Runs the snapshot applier with these options. + /// + /// # Errors + /// + /// This method will return an error if a fatal error occurs during recovery (e.g., the DB is unreachable), + /// or under any of the following conditions: + /// + /// - There are no snapshots on the main node + /// - Storage contains at least one L1 batch pub async fn run( self, connection_pool: &ConnectionPool, main_node_client: &dyn SnapshotsApplierMainNodeClient, blob_store: &dyn ObjectStore, - ) -> anyhow::Result { + ) -> anyhow::Result<()> { let mut backoff = self.initial_retry_backoff; let mut last_error = None; for retry_id in 0..self.retry_count { - let result = - SnapshotsApplier::load_snapshot(connection_pool, main_node_client, blob_store) - .await; + let result = SnapshotsApplier::load_snapshot( + connection_pool, + main_node_client, + blob_store, + &self.health_updater, + ) + .await; match result { - Ok(()) => return Ok(SnapshotsApplierOutcome::Ok), + Ok(()) => { + // Freeze the health check in the "ready" status, so that the snapshot recovery isn't marked + // as "shut down", which would lead to the app considered unhealthy. + self.health_updater.freeze(); + return Ok(()); + } Err(SnapshotsApplierError::Fatal(err)) => { tracing::error!("Fatal error occurred during snapshots recovery: {err:?}"); return Err(err); } - Err(SnapshotsApplierError::EarlyReturn(outcome)) => { - tracing::info!("Cancelled snapshots recovery with the outcome: {outcome:?}"); - return Ok(outcome); - } Err(SnapshotsApplierError::Retryable(err)) => { tracing::warn!("Retryable error occurred during snapshots recovery: {err:?}"); last_error = Some(err); @@ -227,6 +238,9 @@ struct SnapshotsApplier<'a> { main_node_client: &'a dyn SnapshotsApplierMainNodeClient, blob_store: &'a dyn ObjectStore, applied_snapshot_status: SnapshotRecoveryStatus, + health_updater: &'a HealthUpdater, + factory_deps_recovered: bool, + tokens_recovered: bool, } impl<'a> SnapshotsApplier<'a> { @@ -261,7 +275,10 @@ impl<'a> SnapshotsApplier<'a> { SnapshotsApplierError::db(err, "failed checking genesis L1 batch in DB") })?; if !is_genesis_needed { - return Err(SnapshotsApplierOutcome::InitializedWithoutSnapshot.into()); + let err = anyhow::anyhow!( + "node contains a non-genesis L1 batch; snapshot recovery is unsafe" + ); + return Err(SnapshotsApplierError::Fatal(err)); } let latency = latency.observe(); @@ -277,7 +294,10 @@ impl<'a> SnapshotsApplier<'a> { connection_pool: &'a ConnectionPool, main_node_client: &'a dyn SnapshotsApplierMainNodeClient, blob_store: &'a dyn ObjectStore, + health_updater: &'a HealthUpdater, ) -> Result<(), SnapshotsApplierError> { + health_updater.update(HealthStatus::Ready.into()); + let mut storage = connection_pool .access_storage_tagged("snapshots_applier") .await?; @@ -289,32 +309,32 @@ impl<'a> SnapshotsApplier<'a> { Self::prepare_applied_snapshot_status(&mut storage_transaction, main_node_client) .await?; - let mut recovery = Self { + let mut this = Self { connection_pool, main_node_client, blob_store, applied_snapshot_status, + health_updater, + factory_deps_recovered: !created_from_scratch, + tokens_recovered: false, }; METRICS.storage_logs_chunks_count.set( - recovery - .applied_snapshot_status + this.applied_snapshot_status .storage_logs_chunks_processed .len(), ); METRICS.storage_logs_chunks_left_to_process.set( - recovery - .applied_snapshot_status + this.applied_snapshot_status .storage_logs_chunks_left_to_process(), ); + this.update_health(); if created_from_scratch { - recovery - .recover_factory_deps(&mut storage_transaction) - .await?; + this.recover_factory_deps(&mut storage_transaction).await?; storage_transaction .snapshot_recovery_dal() - .insert_initial_recovery_status(&recovery.applied_snapshot_status) + .insert_initial_recovery_status(&this.applied_snapshot_status) .await .map_err(|err| { SnapshotsApplierError::db(err, "failed persisting initial recovery status") @@ -324,9 +344,14 @@ impl<'a> SnapshotsApplier<'a> { SnapshotsApplierError::db(err, "failed committing initial DB transaction") })?; drop(storage); + this.factory_deps_recovered = true; + this.update_health(); + + this.recover_storage_logs().await?; + this.recover_tokens().await?; + this.tokens_recovered = true; + this.update_health(); - recovery.recover_storage_logs().await?; - recovery.recover_tokens().await?; Ok(()) } @@ -335,7 +360,8 @@ impl<'a> SnapshotsApplier<'a> { ) -> Result { let snapshot_response = main_node_client.fetch_newest_snapshot().await?; - let snapshot = snapshot_response.ok_or(SnapshotsApplierOutcome::NoSnapshotsOnMainNode)?; + let snapshot = snapshot_response + .context("no snapshots on main node; snapshot recovery is impossible")?; let l1_batch_number = snapshot.l1_batch_number; let miniblock_number = snapshot.miniblock_number; tracing::info!( @@ -367,6 +393,23 @@ impl<'a> SnapshotsApplier<'a> { }) } + fn update_health(&self) { + let details = SnapshotsApplierHealthDetails { + snapshot_miniblock: self.applied_snapshot_status.miniblock_number, + snapshot_l1_batch: self.applied_snapshot_status.l1_batch_number, + factory_deps_recovered: self.factory_deps_recovered, + tokens_recovered: self.tokens_recovered, + storage_logs_chunk_count: self + .applied_snapshot_status + .storage_logs_chunks_processed + .len(), + // We don't use `self.applied_snapshot_status` here because it's not updated during recovery + storage_logs_chunks_left_to_process: METRICS.storage_logs_chunks_left_to_process.get(), + }; + self.health_updater + .update(Health::from(HealthStatus::Ready).with_details(details)); + } + async fn recover_factory_deps( &mut self, storage: &mut StorageProcessor<'_>, diff --git a/core/lib/snapshots_applier/src/tests/mod.rs b/core/lib/snapshots_applier/src/tests/mod.rs index 80f21aab4d65..a911c34dd99e 100644 --- a/core/lib/snapshots_applier/src/tests/mod.rs +++ b/core/lib/snapshots_applier/src/tests/mod.rs @@ -2,7 +2,6 @@ use std::sync::atomic::{AtomicUsize, Ordering}; -use assert_matches::assert_matches; use test_casing::test_casing; use zksync_object_store::ObjectStoreFactory; use zksync_types::{ @@ -52,11 +51,10 @@ async fn snapshots_creator_can_successfully_recover_db( &object_store }; - let outcome = SnapshotsApplierConfig::for_tests() + SnapshotsApplierConfig::for_tests() .run(&pool, &client, object_store) .await .unwrap(); - assert_matches!(outcome, SnapshotsApplierOutcome::Ok); let mut storage = pool.access_storage().await.unwrap(); let mut recovery_dal = storage.snapshot_recovery_dal(); @@ -92,15 +90,14 @@ async fn snapshots_creator_can_successfully_recover_db( } // Try recovering again. - let outcome = SnapshotsApplierConfig::for_tests() + SnapshotsApplierConfig::for_tests() .run(&pool, &client, object_store) .await .unwrap(); - assert_matches!(outcome, SnapshotsApplierOutcome::Ok); } #[tokio::test] -async fn applier_returns_early_after_genesis() { +async fn applier_errors_after_genesis() { let pool = ConnectionPool::test_pool().await; // We don't want to depend on the core crate, so instead we cheaply emulate it. @@ -149,25 +146,23 @@ async fn applier_returns_early_after_genesis() { let object_store = object_store_factory.create_store().await; let client = MockMainNodeClient::default(); - let outcome = SnapshotsApplierConfig::for_tests() + SnapshotsApplierConfig::for_tests() .run(&pool, &client, &object_store) .await - .unwrap(); - assert_matches!(outcome, SnapshotsApplierOutcome::InitializedWithoutSnapshot); + .unwrap_err(); } #[tokio::test] -async fn applier_returns_early_without_snapshots() { +async fn applier_errors_without_snapshots() { let pool = ConnectionPool::test_pool().await; let object_store_factory = ObjectStoreFactory::mock(); let object_store = object_store_factory.create_store().await; let client = MockMainNodeClient::default(); - let outcome = SnapshotsApplierConfig::for_tests() + SnapshotsApplierConfig::for_tests() .run(&pool, &client, &object_store) .await - .unwrap(); - assert_matches!(outcome, SnapshotsApplierOutcome::NoSnapshotsOnMainNode); + .unwrap_err(); } #[tokio::test] @@ -234,11 +229,10 @@ async fn recovering_tokens() { let (object_store, mut client) = prepare_clients(&expected_status, &storage_logs).await; client.tokens_response = tokens.clone(); - let outcome = SnapshotsApplierConfig::for_tests() + SnapshotsApplierConfig::for_tests() .run(&pool, &client, &object_store) .await .unwrap(); - assert_matches!(outcome, SnapshotsApplierOutcome::Ok); // Check that tokens are successfully restored. let mut storage = pool.access_storage().await.unwrap(); @@ -259,9 +253,8 @@ async fn recovering_tokens() { assert_eq!(token_map, recovered_token_map); // Check that recovering again works and is a no-op. - let outcome = SnapshotsApplierConfig::for_tests() + SnapshotsApplierConfig::for_tests() .run(&pool, &client, &object_store) .await .unwrap(); - assert_matches!(outcome, SnapshotsApplierOutcome::Ok); } diff --git a/core/lib/zksync_core/src/api_server/healthcheck.rs b/core/lib/zksync_core/src/api_server/healthcheck.rs index 8398005f5917..4e880b57a198 100644 --- a/core/lib/zksync_core/src/api_server/healthcheck.rs +++ b/core/lib/zksync_core/src/api_server/healthcheck.rs @@ -1,13 +1,13 @@ -use std::{collections::HashSet, net::SocketAddr, sync::Arc, time::Duration}; +use std::{net::SocketAddr, sync::Arc, time::Duration}; use axum::{extract::State, http::StatusCode, routing::get, Json, Router}; use tokio::sync::watch; -use zksync_health_check::{AppHealth, CheckHealth}; +use zksync_health_check::{AppHealth, AppHealthCheck}; -async fn check_health>( - health_checks: State>, +async fn check_health( + app_health_check: State>, ) -> (StatusCode, Json) { - let response = AppHealth::new(&health_checks).await; + let response = app_health_check.check_health().await; let response_code = if response.is_healthy() { StatusCode::OK } else { @@ -16,31 +16,18 @@ async fn check_health>( (response_code, Json(response)) } -async fn run_server( +async fn run_server( bind_address: &SocketAddr, - health_checks: Vec, + app_health_check: Arc, mut stop_receiver: watch::Receiver, -) where - T: AsRef + Send + Sync + 'static, -{ - let mut health_check_names = HashSet::with_capacity(health_checks.len()); - for check in &health_checks { - let health_check_name = check.as_ref().name(); - if !health_check_names.insert(health_check_name) { - tracing::warn!( - "Health check with name `{health_check_name}` is defined multiple times; only the last mention \ - will be present in `/health` endpoint output" - ); - } - } +) { tracing::debug!( - "Starting healthcheck server with checks {health_check_names:?} on {bind_address}" + "Starting healthcheck server with checks {app_health_check:?} on {bind_address}" ); - let health_checks = Arc::from(health_checks); let app = Router::new() .route("/health", get(check_health)) - .with_state(health_checks); + .with_state(app_health_check); axum::Server::bind(bind_address) .serve(app.into_make_service()) @@ -62,13 +49,10 @@ pub struct HealthCheckHandle { } impl HealthCheckHandle { - pub fn spawn_server(addr: SocketAddr, healthchecks: Vec) -> Self - where - T: AsRef + Send + Sync + 'static, - { + pub fn spawn_server(addr: SocketAddr, app_health_check: Arc) -> Self { let (stop_sender, stop_receiver) = watch::channel(false); let server = tokio::spawn(async move { - run_server(&addr, healthchecks, stop_receiver).await; + run_server(&addr, app_health_check, stop_receiver).await; }); Self { diff --git a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs index 8cf1dd3a96ca..8fe0380e7510 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs @@ -25,6 +25,7 @@ use zksync_types::{ MAX_NEW_FACTORY_DEPS, U256, }; use zksync_utils::h256_to_u256; +use zksync_web3_decl::jsonrpsee::http_client::HttpClient; pub(super) use self::{proxy::TxProxy, result::SubmitTxError}; use crate::{ @@ -164,8 +165,8 @@ impl TxSenderBuilder { self } - pub fn with_tx_proxy(mut self, main_node_url: &str) -> Self { - self.proxy = Some(TxProxy::new(main_node_url)); + pub fn with_tx_proxy(mut self, client: HttpClient) -> Self { + self.proxy = Some(TxProxy::new(client)); self } diff --git a/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs b/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs index a16ee2d07bbb..5cd228745980 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs @@ -14,7 +14,7 @@ use zksync_types::{ }; use zksync_web3_decl::{ error::{ClientRpcContext, EnrichedClientResult}, - jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, + jsonrpsee::http_client::HttpClient, namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; @@ -109,8 +109,7 @@ pub struct TxProxy { } impl TxProxy { - pub fn new(main_node_url: &str) -> Self { - let client = HttpClientBuilder::default().build(main_node_url).unwrap(); + pub fn new(client: HttpClient) -> Self { Self { client, tx_cache: TxCache::default(), diff --git a/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs b/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs index 8c8cf4e3f90e..51dab49451d4 100644 --- a/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs +++ b/core/lib/zksync_core/src/l1_gas_price/main_node_fetcher.rs @@ -6,9 +6,7 @@ use std::{ use tokio::sync::watch::Receiver; use zksync_types::fee_model::FeeParams; use zksync_web3_decl::{ - error::ClientRpcContext, - jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, - namespaces::ZksNamespaceClient, + error::ClientRpcContext, jsonrpsee::http_client::HttpClient, namespaces::ZksNamespaceClient, }; use crate::fee_model::BatchFeeModelInputProvider; @@ -28,19 +26,13 @@ pub struct MainNodeFeeParamsFetcher { } impl MainNodeFeeParamsFetcher { - pub fn new(main_node_url: &str) -> Self { + pub fn new(client: HttpClient) -> Self { Self { - client: Self::build_client(main_node_url), + client, main_node_fee_params: RwLock::new(FeeParams::sensible_v1_default()), } } - fn build_client(main_node_url: &str) -> HttpClient { - HttpClientBuilder::default() - .build(main_node_url) - .expect("Unable to create a main node client") - } - pub async fn run(self: Arc, stop_receiver: Receiver) -> anyhow::Result<()> { loop { if *stop_receiver.borrow() { diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index baf622375b3a..f7b1f9fb4a7d 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -31,7 +31,7 @@ use zksync_eth_client::{ clients::{PKSigningClient, QueryClient}, CallFunctionArgs, EthInterface, }; -use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; +use zksync_health_check::{AppHealthCheck, HealthStatus, ReactiveHealthCheck}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; use zksync_queued_job_processor::JobProcessor; use zksync_state::PostgresStorageCaches; @@ -328,7 +328,7 @@ pub async fn initialize_components( .await .context("failed to build replica_connection_pool")?; - let mut healthchecks: Vec> = Vec::new(); + let app_health = Arc::new(AppHealthCheck::default()); let contracts_config = configs .contracts_config .clone() @@ -369,7 +369,7 @@ pub async fn initialize_components( let (prometheus_health_check, prometheus_health_updater) = ReactiveHealthCheck::new("prometheus_exporter"); - healthchecks.push(Box::new(prometheus_health_check)); + app_health.insert_component(prometheus_health_check); let prometheus_task = prom_config.run(stop_receiver.clone()); let prometheus_task = tokio::spawn(async move { prometheus_health_updater.update(HealthStatus::Ready.into()); @@ -443,7 +443,7 @@ pub async fn initialize_components( .context("run_http_api")?; task_futures.extend(server_handles.tasks); - healthchecks.push(Box::new(server_handles.health_check)); + app_health.insert_component(server_handles.health_check); let elapsed = started_at.elapsed(); APP_METRICS.init_latency[&InitStage::HttpApi].set(elapsed); tracing::info!( @@ -485,7 +485,7 @@ pub async fn initialize_components( .context("run_ws_api")?; task_futures.extend(server_handles.tasks); - healthchecks.push(Box::new(server_handles.health_check)); + app_health.insert_component(server_handles.health_check); let elapsed = started_at.elapsed(); APP_METRICS.init_latency[&InitStage::WsApi].set(elapsed); tracing::info!( @@ -685,7 +685,7 @@ pub async fn initialize_components( add_trees_to_task_futures( configs, &mut task_futures, - &mut healthchecks, + &app_health, &components, &store_factory, stop_receiver.clone(), @@ -738,23 +738,22 @@ pub async fn initialize_components( .await .context("failed to build commitment_generator_pool")?; let commitment_generator = CommitmentGenerator::new(commitment_generator_pool); - healthchecks.push(Box::new(commitment_generator.health_check())); + app_health.insert_component(commitment_generator.health_check()); task_futures.push(tokio::spawn( commitment_generator.run(stop_receiver.clone()), )); } // Run healthcheck server for all components. - healthchecks.push(Box::new(ConnectionPoolHealthCheck::new( - replica_connection_pool, - ))); + let db_health_check = ConnectionPoolHealthCheck::new(replica_connection_pool); + app_health.insert_custom_component(Arc::new(db_health_check)); let healtcheck_api_config = configs .health_check_config .clone() .context("health_check_config")?; let health_check_handle = - HealthCheckHandle::spawn_server(healtcheck_api_config.bind_addr(), healthchecks); + HealthCheckHandle::spawn_server(healtcheck_api_config.bind_addr(), app_health); if let Some(task) = gas_adjuster.run_if_initialized(stop_receiver.clone()) { task_futures.push(task); @@ -838,7 +837,7 @@ async fn add_state_keeper_to_task_futures( async fn add_trees_to_task_futures( configs: &TempConfigStore, task_futures: &mut Vec>>, - healthchecks: &mut Vec>, + app_health: &AppHealthCheck, components: &[Component], store_factory: &ObjectStoreFactory, stop_receiver: watch::Receiver, @@ -873,7 +872,7 @@ async fn add_trees_to_task_futures( run_tree( task_futures, - healthchecks, + app_health, &postgres_config, &db_config.merkle_tree, api_config, @@ -888,7 +887,7 @@ async fn add_trees_to_task_futures( #[allow(clippy::too_many_arguments)] async fn run_tree( task_futures: &mut Vec>>, - healthchecks: &mut Vec>, + app_health: &AppHealthCheck, postgres_config: &PostgresConfig, merkle_tree_config: &MerkleTreeConfig, api_config: Option<&MerkleTreeApiConfig>, @@ -921,7 +920,7 @@ async fn run_tree( } let tree_health_check = metadata_calculator.tree_health_check(); - healthchecks.push(Box::new(tree_health_check)); + app_health.insert_component(tree_health_check); let pool = ConnectionPool::singleton(postgres_config.master_url()?) .build() .await diff --git a/core/lib/zksync_core/src/reorg_detector/mod.rs b/core/lib/zksync_core/src/reorg_detector/mod.rs index 691b58361bf2..406adb2ccbef 100644 --- a/core/lib/zksync_core/src/reorg_detector/mod.rs +++ b/core/lib/zksync_core/src/reorg_detector/mod.rs @@ -8,10 +8,7 @@ use zksync_health_check::{Health, HealthStatus, HealthUpdater, ReactiveHealthChe use zksync_types::{L1BatchNumber, MiniblockNumber, H256}; use zksync_web3_decl::{ error::{ClientRpcContext, EnrichedClientError, EnrichedClientResult}, - jsonrpsee::{ - core::ClientError as RpcError, - http_client::{HttpClient, HttpClientBuilder}, - }, + jsonrpsee::{core::ClientError as RpcError, http_client::HttpClient}, namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; @@ -213,10 +210,7 @@ pub struct ReorgDetector { impl ReorgDetector { const DEFAULT_SLEEP_INTERVAL: Duration = Duration::from_secs(5); - pub fn new(url: &str, pool: ConnectionPool) -> Self { - let client = HttpClientBuilder::default() - .build(url) - .expect("Failed to create HTTP client"); + pub fn new(client: HttpClient, pool: ConnectionPool) -> Self { let (health_check, health_updater) = ReactiveHealthCheck::new("reorg_detector"); Self { client: Box::new(client), diff --git a/core/lib/zksync_core/src/sync_layer/batch_status_updater/mod.rs b/core/lib/zksync_core/src/sync_layer/batch_status_updater/mod.rs index 8c14f937dd83..a6a1835a9f18 100644 --- a/core/lib/zksync_core/src/sync_layer/batch_status_updater/mod.rs +++ b/core/lib/zksync_core/src/sync_layer/batch_status_updater/mod.rs @@ -16,7 +16,7 @@ use zksync_types::{ }; use zksync_web3_decl::{ error::{ClientRpcContext, EnrichedClientError, EnrichedClientResult}, - jsonrpsee::http_client::{HttpClient, HttpClientBuilder}, + jsonrpsee::http_client::HttpClient, namespaces::ZksNamespaceClient, }; @@ -254,15 +254,8 @@ pub struct BatchStatusUpdater { impl BatchStatusUpdater { const DEFAULT_SLEEP_INTERVAL: Duration = Duration::from_secs(5); - pub fn new(main_node_url: &str, pool: ConnectionPool) -> anyhow::Result { - let client = HttpClientBuilder::default() - .build(main_node_url) - .context("Unable to create a main node client")?; - Ok(Self::from_parts( - Box::new(client), - pool, - Self::DEFAULT_SLEEP_INTERVAL, - )) + pub fn new(client: HttpClient, pool: ConnectionPool) -> Self { + Self::from_parts(Box::new(client), pool, Self::DEFAULT_SLEEP_INTERVAL) } fn from_parts( diff --git a/core/node/node_framework/src/implementations/layers/healtcheck_server.rs b/core/node/node_framework/src/implementations/layers/healtcheck_server.rs index 8527d5323415..bc1dfd657926 100644 --- a/core/node/node_framework/src/implementations/layers/healtcheck_server.rs +++ b/core/node/node_framework/src/implementations/layers/healtcheck_server.rs @@ -1,11 +1,11 @@ -use std::fmt; +use std::sync::Arc; use zksync_config::configs::api::HealthCheckConfig; use zksync_core::api_server::healthcheck::HealthCheckHandle; +use zksync_health_check::AppHealthCheck; use crate::{ - implementations::resources::healthcheck::HealthCheckResource, - resource::ResourceCollection, + implementations::resources::healthcheck::AppHealthCheckResource, service::{ServiceContext, StopReceiver}, task::Task, wiring_layer::{WiringError, WiringLayer}, @@ -32,13 +32,11 @@ impl WiringLayer for HealthCheckLayer { } async fn wire(self: Box, mut node: ServiceContext<'_>) -> Result<(), WiringError> { - let healthchecks = node - .get_resource_or_default::>() - .await; + let AppHealthCheckResource(app_health_check) = node.get_resource_or_default().await; let task = HealthCheckTask { config: self.0, - healthchecks, + app_health_check, }; node.add_task(Box::new(task)); @@ -46,17 +44,10 @@ impl WiringLayer for HealthCheckLayer { } } +#[derive(Debug)] struct HealthCheckTask { config: HealthCheckConfig, - healthchecks: ResourceCollection, -} - -impl fmt::Debug for HealthCheckTask { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("HealthCheckTask") - .field("config", &self.config) - .finish_non_exhaustive() - } + app_health_check: Arc, } #[async_trait::async_trait] @@ -66,9 +57,8 @@ impl Task for HealthCheckTask { } async fn run(mut self: Box, mut stop_receiver: StopReceiver) -> anyhow::Result<()> { - let healthchecks = self.healthchecks.resolve().await; - - let handle = HealthCheckHandle::spawn_server(self.config.bind_addr(), healthchecks); + let handle = + HealthCheckHandle::spawn_server(self.config.bind_addr(), self.app_health_check.clone()); stop_receiver.0.changed().await?; handle.stop().await; diff --git a/core/node/node_framework/src/implementations/layers/metadata_calculator.rs b/core/node/node_framework/src/implementations/layers/metadata_calculator.rs index 292441dcab7b..5f9ea646304f 100644 --- a/core/node/node_framework/src/implementations/layers/metadata_calculator.rs +++ b/core/node/node_framework/src/implementations/layers/metadata_calculator.rs @@ -4,10 +4,9 @@ use zksync_storage::RocksDB; use crate::{ implementations::resources::{ - healthcheck::HealthCheckResource, object_store::ObjectStoreResource, + healthcheck::AppHealthCheckResource, object_store::ObjectStoreResource, pools::MasterPoolResource, }, - resource::ResourceCollection, service::{ServiceContext, StopReceiver}, task::Task, wiring_layer::{WiringError, WiringLayer}, @@ -50,14 +49,8 @@ impl WiringLayer for MetadataCalculatorLayer { let metadata_calculator = MetadataCalculator::new(self.0, object_store.map(|os| os.0)).await?; - let healthchecks = context - .get_resource_or_default::>() - .await; - healthchecks - .push(HealthCheckResource::new( - metadata_calculator.tree_health_check(), - )) - .expect("Wiring stage"); + let AppHealthCheckResource(app_health) = context.get_resource_or_default().await; + app_health.insert_component(metadata_calculator.tree_health_check()); let task = Box::new(MetadataCalculatorTask { metadata_calculator, diff --git a/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs b/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs index 5fca61119b94..0a7e2ee84898 100644 --- a/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs +++ b/core/node/node_framework/src/implementations/layers/prometheus_exporter.rs @@ -2,8 +2,7 @@ use prometheus_exporter::PrometheusExporterConfig; use zksync_health_check::{HealthStatus, HealthUpdater, ReactiveHealthCheck}; use crate::{ - implementations::resources::healthcheck::HealthCheckResource, - resource::ResourceCollection, + implementations::resources::healthcheck::AppHealthCheckResource, service::{ServiceContext, StopReceiver}, task::Task, wiring_layer::{WiringError, WiringLayer}, @@ -34,12 +33,8 @@ impl WiringLayer for PrometheusExporterLayer { let (prometheus_health_check, prometheus_health_updater) = ReactiveHealthCheck::new("prometheus_exporter"); - let healthchecks = node - .get_resource_or_default::>() - .await; - healthchecks - .push(HealthCheckResource::new(prometheus_health_check)) - .expect("Wiring stage"); + let AppHealthCheckResource(app_health) = node.get_resource_or_default().await; + app_health.insert_component(prometheus_health_check); let task = Box::new(PrometheusExporterTask { config: self.0, diff --git a/core/node/node_framework/src/implementations/resources/healthcheck.rs b/core/node/node_framework/src/implementations/resources/healthcheck.rs index 5b752e33d59b..59b90960c102 100644 --- a/core/node/node_framework/src/implementations/resources/healthcheck.rs +++ b/core/node/node_framework/src/implementations/resources/healthcheck.rs @@ -1,36 +1,16 @@ -use std::{fmt, sync::Arc}; +use std::sync::Arc; +use zksync_health_check::AppHealthCheck; // Public re-exports from external crate to minimize the required dependencies. pub use zksync_health_check::{CheckHealth, ReactiveHealthCheck}; use crate::resource::Resource; -/// Wrapper for a generic health check. -#[derive(Clone)] -pub struct HealthCheckResource(Arc); +#[derive(Debug, Clone, Default)] +pub struct AppHealthCheckResource(pub Arc); -impl HealthCheckResource { - pub fn new(check: impl CheckHealth + 'static) -> Self { - Self(Arc::new(check)) - } -} - -impl fmt::Debug for HealthCheckResource { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("HealthCheckResource") - .field("name", &self.0.name()) - .finish_non_exhaustive() - } -} - -impl Resource for HealthCheckResource { +impl Resource for AppHealthCheckResource { fn resource_id() -> crate::resource::ResourceId { - "common/health_check".into() - } -} - -impl AsRef for HealthCheckResource { - fn as_ref(&self) -> &dyn CheckHealth { - self.0.as_ref() + "common/app_health_check".into() } } diff --git a/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts b/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts index 3d0d48164702..05ad1658580a 100644 --- a/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts +++ b/core/tests/snapshot-recovery-test/tests/snapshot-recovery.test.ts @@ -1,12 +1,11 @@ import { expect } from 'chai'; +import fetch, { FetchError } from 'node-fetch'; import * as protobuf from 'protobufjs'; import * as zlib from 'zlib'; import * as zkweb3 from 'zksync-web3'; -import fs from 'node:fs/promises'; -import { ChildProcess, spawn, exec, ChildProcessByStdio } from 'node:child_process'; +import fs, { FileHandle } from 'node:fs/promises'; +import { ChildProcess, spawn, exec } from 'node:child_process'; import path from 'node:path'; -import readline from 'node:readline/promises'; -import { Readable, Writable } from 'node:stream'; import { promisify } from 'node:util'; interface AllSnapshotsResponse { @@ -36,11 +35,41 @@ interface StorageLog { } interface TokenInfo { - // FIXME: why isn't case changed? readonly l1_address: string; readonly l2_address: string; } +interface Health { + readonly status: string; + readonly details?: T; +} + +interface SnapshotRecoveryDetails { + readonly snapshot_l1_batch: number; + readonly snapshot_miniblock: number; + readonly factory_deps_recovered: boolean; + readonly tokens_recovered: boolean; + readonly storage_logs_chunks_left_to_process: number; +} + +interface ConsistencyCheckerDetails { + readonly first_checked_batch?: number; + readonly last_checked_batch?: number; +} + +interface ReorgDetectorDetails { + readonly last_correct_l1_batch?: number; + readonly last_correct_miniblock?: number; +} + +interface HealthCheckResponse { + components: { + snapshot_recovery?: Health; + consistency_checker?: Health; + reorg_detector?: Health; + }; +} + /** * Assumptions: * @@ -50,8 +79,6 @@ interface TokenInfo { */ describe('snapshot recovery', () => { const STORAGE_LOG_SAMPLE_PROBABILITY = 0.1; - const IMPORTANT_LINE_REGEX = - /zksync_external_node::init|zksync_core::consistency_checker|zksync_core::reorg_detector/; const homeDir = process.env.ZKSYNC_HOME!!; const externalNodeEnv = { @@ -62,7 +89,8 @@ describe('snapshot recovery', () => { let snapshotMetadata: GetSnapshotResponse; let mainNode: zkweb3.Provider; let externalNode: zkweb3.Provider; - let externalNodeProcess: ChildProcessByStdio; + let externalNodeLogs: FileHandle; + let externalNodeProcess: ChildProcess; before(async () => { expect(process.env.ZKSYNC_ENV, '`ZKSYNC_ENV` should not be set to allow running both server and EN components') @@ -76,6 +104,7 @@ describe('snapshot recovery', () => { if (externalNodeProcess) { externalNodeProcess.kill(); await killExternalNode(); + await externalNodeLogs.close(); } }); @@ -105,6 +134,7 @@ describe('snapshot recovery', () => { await waitForProcess(childProcess); } finally { childProcess.kill(); + await logs.close(); } }); @@ -183,41 +213,72 @@ describe('snapshot recovery', () => { }); step('initialize external node', async () => { - const logs = await fs.open('snapshot-recovery.log', 'a'); - await logs.truncate(); + externalNodeLogs = await fs.open('snapshot-recovery.log', 'w'); externalNodeProcess = spawn('zk external-node -- --enable-snapshots-recovery', { cwd: homeDir, - stdio: [null, 'pipe', 'inherit'], + stdio: [null, externalNodeLogs.fd, externalNodeLogs.fd], shell: true, env: externalNodeEnv }); + let recoveryFinished = false; let consistencyCheckerSucceeded = false; let reorgDetectorSucceeded = false; - const rl = readline.createInterface({ - input: externalNodeProcess.stdout, - crlfDelay: Infinity - }); - // TODO: use a more reliable method to detect recovery success (e.g., based on health checks) - for await (const line of rl) { - if (IMPORTANT_LINE_REGEX.test(line)) { - console.log('en> ' + line); + while (!recoveryFinished || !consistencyCheckerSucceeded || !reorgDetectorSucceeded) { + await sleep(1000); + const health = await getExternalNodeHealth(); + if (health === null) { + continue; } - await fs.appendFile(logs, line + '\n'); - if (/L1 batch #\d+ is consistent with L1/.test(line)) { - console.log('Consistency checker successfully checked post-snapshot L1 batch'); - consistencyCheckerSucceeded = true; + if (!recoveryFinished) { + const status = health.components.snapshot_recovery?.status; + expect(status).to.be.oneOf([undefined, 'ready']); + const details = health.components.snapshot_recovery?.details; + if (details !== undefined) { + console.log('Received snapshot recovery health details', details); + expect(details.snapshot_l1_batch).to.equal(snapshotMetadata.l1BatchNumber); + expect(details.snapshot_miniblock).to.equal(snapshotMetadata.miniblockNumber); + + if ( + details.factory_deps_recovered && + details.tokens_recovered && + details.storage_logs_chunks_left_to_process === 0 + ) { + console.log('Snapshot recovery is complete'); + recoveryFinished = true; + } + } } - if (/No reorg at L1 batch #\d+/.test(line)) { - console.log('Reorg detector successfully checked post-snapshot L1 batch'); - reorgDetectorSucceeded = true; + + if (!consistencyCheckerSucceeded) { + const status = health.components.consistency_checker?.status; + expect(status).to.be.oneOf([undefined, 'ready']); + const details = health.components.consistency_checker?.details; + if (details !== undefined) { + console.log('Received consistency checker health details', details); + if (details.first_checked_batch !== undefined && details.last_checked_batch !== undefined) { + expect(details.first_checked_batch).to.equal(snapshotMetadata.l1BatchNumber + 1); + expect(details.last_checked_batch).to.be.greaterThan(snapshotMetadata.l1BatchNumber); + consistencyCheckerSucceeded = true; + } + } } - if (consistencyCheckerSucceeded && reorgDetectorSucceeded) { - break; + if (!reorgDetectorSucceeded) { + const status = health.components.reorg_detector?.status; + expect(status).to.be.oneOf([undefined, 'ready']); + const details = health.components.reorg_detector?.details; + if (details !== undefined) { + console.log('Received reorg detector health details', details); + if (details.last_correct_l1_batch !== undefined && details.last_correct_miniblock !== undefined) { + expect(details.last_correct_l1_batch).to.be.greaterThan(snapshotMetadata.l1BatchNumber); + expect(details.last_correct_miniblock).to.be.greaterThan(snapshotMetadata.miniblockNumber); + reorgDetectorSucceeded = true; + } + } } } @@ -283,6 +344,26 @@ async function decompressGzip(filePath: string): Promise { }); } +async function sleep(millis: number) { + await new Promise((resolve) => setTimeout(resolve, millis)); +} + +async function getExternalNodeHealth() { + const EXTERNAL_NODE_HEALTH_URL = 'http://127.0.0.1:3081/health'; + + try { + const response: HealthCheckResponse = await fetch(EXTERNAL_NODE_HEALTH_URL).then((response) => response.json()); + return response; + } catch (e) { + let displayedError = e; + if (e instanceof FetchError && e.code === 'ECONNREFUSED') { + displayedError = '(connection refused)'; // Don't spam logs with "connection refused" messages + } + console.log('Request to EN health check server failed', displayedError); + return null; + } +} + async function killExternalNode() { interface ChildProcessError extends Error { readonly code: number | null; diff --git a/etc/env/ext-node.toml b/etc/env/ext-node.toml index c14ecf068147..64765c87d9f3 100644 --- a/etc/env/ext-node.toml +++ b/etc/env/ext-node.toml @@ -64,6 +64,7 @@ zksync_consensus_network=info,\ zksync_consensus_storage=info,\ zksync_core=debug,\ zksync_dal=info,\ +zksync_health_check=debug,\ zksync_eth_client=info,\ zksync_storage=info,\ zksync_merkle_tree=info,\ From 6f63c53549fda7e253e1d4cb4ed42ec6a2e3e9f1 Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Wed, 21 Feb 2024 08:46:17 +0100 Subject: [PATCH 012/106] feat(prover): Adding first support for 4844 circuit (#1155) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Adding first part of support for 4844 circuit in prover. * Added it to prover enums (like proof wrapper etc). * But it is not connected to witness generators yet. ## Why ❔ * This is a part of the larger effort to handle 4844 blob support for era. --------- Co-authored-by: EmilLuta Co-authored-by: Emil --- checks-config/era.dic | 3 +- prover/proof_fri_compressor/src/compressor.rs | 3 ++ .../src/gpu_prover_job_processor.rs | 6 +++ prover/prover_fri/src/prover_job_processor.rs | 44 ++++++++++++++++++- prover/prover_fri/src/socket_listener.rs | 8 ++++ prover/prover_fri/src/utils.rs | 13 ++++-- prover/prover_fri/tests/basic_test.rs | 2 +- prover/prover_fri_types/src/lib.rs | 5 ++- prover/prover_fri_utils/src/lib.rs | 1 + .../witness_generator/src/leaf_aggregation.rs | 3 ++ .../witness_generator/src/node_aggregation.rs | 1 + prover/witness_generator/src/scheduler.rs | 3 ++ .../witness_vector_generator/src/generator.rs | 4 ++ 13 files changed, 88 insertions(+), 8 deletions(-) diff --git a/checks-config/era.dic b/checks-config/era.dic index 22d6189ca671..6ee220430876 100644 --- a/checks-config/era.dic +++ b/checks-config/era.dic @@ -900,4 +900,5 @@ downcasting parameterized reimplementation composability -md5 \ No newline at end of file +md5 +shivini diff --git a/prover/proof_fri_compressor/src/compressor.rs b/prover/proof_fri_compressor/src/compressor.rs index 521b184c2d6a..ee1db17e0001 100644 --- a/prover/proof_fri_compressor/src/compressor.rs +++ b/prover/proof_fri_compressor/src/compressor.rs @@ -153,6 +153,9 @@ impl JobProcessor for ProofCompressor { let scheduler_proof = match fri_proof { FriProofWrapper::Base(_) => anyhow::bail!("Must be a scheduler proof not base layer"), FriProofWrapper::Recursive(proof) => proof, + FriProofWrapper::Eip4844(_) => { + anyhow::bail!("Must be a scheduler proof not 4844") + } }; Ok(Some((l1_batch_number, scheduler_proof))) } diff --git a/prover/prover_fri/src/gpu_prover_job_processor.rs b/prover/prover_fri/src/gpu_prover_job_processor.rs index fc0030bfb6fc..72e0c4b7ac2e 100644 --- a/prover/prover_fri/src/gpu_prover_job_processor.rs +++ b/prover/prover_fri/src/gpu_prover_job_processor.rs @@ -3,6 +3,7 @@ pub mod gpu_prover { use std::{collections::HashMap, sync::Arc, time::Instant}; use anyhow::Context as _; + use circuit_definitions::eip4844_proof_config; use shivini::{gpu_prove_from_external_witness_data, ProverContext}; use tokio::task::JoinHandle; use zksync_config::configs::{fri_prover_group::FriProverGroupConfig, FriProverConfig}; @@ -137,6 +138,10 @@ pub mod gpu_prover { base_layer_proof_config(), recursive_circuit.numeric_circuit_type(), ), + CircuitWrapper::Eip4844(_) => ( + eip4844_proof_config(), + ProverServiceDataKey::eip4844().circuit_id, + ), }; let started_at = Instant::now(); @@ -180,6 +185,7 @@ pub mod gpu_prover { CircuitWrapper::Recursive(_) => FriProofWrapper::Recursive( ZkSyncRecursionLayerProof::from_inner(circuit_id, proof), ), + CircuitWrapper::Eip4844(_) => FriProofWrapper::Eip4844(proof), }; ProverArtifacts::new(prover_job.block_number, proof_wrapper) } diff --git a/prover/prover_fri/src/prover_job_processor.rs b/prover/prover_fri/src/prover_job_processor.rs index 77c32ce73f34..083c1cd9d868 100644 --- a/prover/prover_fri/src/prover_job_processor.rs +++ b/prover/prover_fri/src/prover_job_processor.rs @@ -1,8 +1,11 @@ use std::{collections::HashMap, sync::Arc, time::Instant}; use anyhow::Context as _; +use circuit_definitions::{circuit_definitions::eip4844::EIP4844Circuit, eip4844_proof_config}; use tokio::task::JoinHandle; -use zkevm_test_harness::prover_utils::{prove_base_layer_circuit, prove_recursion_layer_circuit}; +use zkevm_test_harness::prover_utils::{ + prove_base_layer_circuit, prove_eip4844_circuit, prove_recursion_layer_circuit, +}; use zksync_config::configs::{fri_prover_group::FriProverGroupConfig, FriProverConfig}; use zksync_dal::ConnectionPool; use zksync_env_config::FromEnv; @@ -110,10 +113,49 @@ impl Prover { CircuitWrapper::Recursive(recursive_circuit) => { Self::prove_recursive_layer(job.job_id, recursive_circuit, config, setup_data) } + CircuitWrapper::Eip4844(circuit) => { + Self::prove_eip4844(job.job_id, circuit, setup_data) + } }; ProverArtifacts::new(job.block_number, proof) } + fn prove_eip4844( + job_id: u32, + circuit: EIP4844Circuit, + artifact: Arc, + ) -> FriProofWrapper { + let worker = Worker::new(); + let started_at = Instant::now(); + + let proof = prove_eip4844_circuit::( + circuit.clone(), + &worker, + eip4844_proof_config(), + &artifact.setup_base, + &artifact.setup, + &artifact.setup_tree, + &artifact.vk, + &artifact.vars_hint, + &artifact.wits_hint, + &artifact.finalization_hint, + ); + + let label = CircuitLabels { + circuit_type: ProverServiceDataKey::eip4844().circuit_id, + layer: Layer::Base, + }; + METRICS.proof_generation_time[&label].observe(started_at.elapsed()); + + verify_proof( + &CircuitWrapper::Eip4844(circuit), + &proof, + &artifact.vk, + job_id, + ); + FriProofWrapper::Eip4844(proof) + } + fn prove_recursive_layer( job_id: u32, circuit: ZkSyncRecursiveLayerCircuit, diff --git a/prover/prover_fri/src/socket_listener.rs b/prover/prover_fri/src/socket_listener.rs index 9fc7ee30149b..911762392b1c 100644 --- a/prover/prover_fri/src/socket_listener.rs +++ b/prover/prover_fri/src/socket_listener.rs @@ -196,6 +196,14 @@ pub mod gpu_socket_listener { .context("get_finalization_hints()")?; init_recursive_layer_cs_for_repeated_proving(recursive_circuit, &finalization_hint) } + CircuitWrapper::Eip4844(_) => { + let key = ProverServiceDataKey::eip4844(); + let finalization_hint = keystore + .load_finalization_hints(key) + .context("get_finalization_hints()")?; + // Check shivini support. + todo!(); + } }; tracing::info!( "Successfully generated assembly without witness vector for job: {}, took: {:?}", diff --git a/prover/prover_fri/src/utils.rs b/prover/prover_fri/src/utils.rs index b111f22605c4..d405a84a59ea 100644 --- a/prover/prover_fri/src/utils.rs +++ b/prover/prover_fri/src/utils.rs @@ -3,7 +3,9 @@ use std::{sync::Arc, time::Instant}; use tokio::sync::Mutex; -use zkevm_test_harness::prover_utils::{verify_base_layer_proof, verify_recursion_layer_proof}; +use zkevm_test_harness::prover_utils::{ + verify_base_layer_proof, verify_eip4844_proof, verify_recursion_layer_proof, +}; use zksync_dal::StorageProcessor; use zksync_object_store::ObjectStore; use zksync_prover_fri_types::{ @@ -96,6 +98,7 @@ pub async fn save_proof( } _ => (recursive_circuit.numeric_circuit_type(), false), }, + FriProofWrapper::Eip4844(_) => (ProverServiceDataKey::eip4844().circuit_id, false), }; let blob_save_started_at = Instant::now(); @@ -143,14 +146,16 @@ pub fn verify_proof( verify_recursion_layer_proof::(recursive_circuit, proof, vk), recursive_circuit.numeric_circuit_type(), ), + CircuitWrapper::Eip4844(circuit) => ( + verify_eip4844_proof::(circuit, proof, vk), + ProverServiceDataKey::eip4844().circuit_id, + ), }; METRICS.proof_verification_time[&circuit_id.to_string()].observe(started_at.elapsed()); if !is_valid { - let msg = format!( - "Failed to verify base layer proof for job-id: {job_id} circuit_type {circuit_id}" - ); + let msg = format!("Failed to verify proof for job-id: {job_id} circuit_type {circuit_id}"); tracing::error!("{}", msg); panic!("{}", msg); } diff --git a/prover/prover_fri/tests/basic_test.rs b/prover/prover_fri/tests/basic_test.rs index 38654dcb37c3..66103a5e0878 100644 --- a/prover/prover_fri/tests/basic_test.rs +++ b/prover/prover_fri/tests/basic_test.rs @@ -54,7 +54,7 @@ async fn prover_and_assert_base_layer( .context("circuit missing")?; let circuit = match &circuit_wrapper { CircuitWrapper::Base(base) => base.clone(), - CircuitWrapper::Recursive(_) => anyhow::bail!("Expected base layer circuit"), + _ => anyhow::bail!("Expected base layer circuit"), }; let keystore = Keystore::default(); let circuit_setup_data = generate_setup_data_common( diff --git a/prover/prover_fri_types/src/lib.rs b/prover/prover_fri_types/src/lib.rs index 56adb330f574..3b91de5a2b0e 100644 --- a/prover/prover_fri_types/src/lib.rs +++ b/prover/prover_fri_types/src/lib.rs @@ -5,7 +5,8 @@ use circuit_definitions::{ aux_definitions::witness_oracle::VmWitnessOracle, boojum::{cs::implementations::witness::WitnessVec, field::goldilocks::GoldilocksField}, circuit_definitions::{ - base_layer::{ZkSyncBaseLayerCircuit, ZkSyncBaseLayerProof}, + base_layer::{ZkSyncBaseLayerCircuit, ZkSyncBaseLayerProof, ZkSyncBaseProof}, + eip4844::EIP4844Circuit, recursion_layer::{ ZkSyncRecursionLayerProof, ZkSyncRecursionLayerStorageType, ZkSyncRecursiveLayerCircuit, }, @@ -34,6 +35,7 @@ pub enum CircuitWrapper { >, ), Recursive(ZkSyncRecursiveLayerCircuit), + Eip4844(EIP4844Circuit), } impl StoredObject for CircuitWrapper { @@ -58,6 +60,7 @@ impl StoredObject for CircuitWrapper { pub enum FriProofWrapper { Base(ZkSyncBaseLayerProof), Recursive(ZkSyncRecursionLayerProof), + Eip4844(ZkSyncBaseProof), } impl StoredObject for FriProofWrapper { diff --git a/prover/prover_fri_utils/src/lib.rs b/prover/prover_fri_utils/src/lib.rs index 39971555f932..4f17fb970810 100644 --- a/prover/prover_fri_utils/src/lib.rs +++ b/prover/prover_fri_utils/src/lib.rs @@ -103,6 +103,7 @@ pub fn get_numeric_circuit_id(circuit_wrapper: &CircuitWrapper) -> u8 { match circuit_wrapper { CircuitWrapper::Base(circuit) => circuit.numeric_circuit_type(), CircuitWrapper::Recursive(circuit) => circuit.numeric_circuit_type(), + CircuitWrapper::Eip4844(_) => ProverServiceDataKey::eip4844().circuit_id, } } diff --git a/prover/witness_generator/src/leaf_aggregation.rs b/prover/witness_generator/src/leaf_aggregation.rs index da2711e7a268..cd5ac65507db 100644 --- a/prover/witness_generator/src/leaf_aggregation.rs +++ b/prover/witness_generator/src/leaf_aggregation.rs @@ -229,6 +229,9 @@ pub async fn prepare_leaf_aggregation_job( FriProofWrapper::Recursive(_) => { anyhow::bail!("Expected only base proofs for leaf agg {}", metadata.id); } + FriProofWrapper::Eip4844(_) => { + anyhow::bail!("EIP4844 should be run as a leaf."); + } } } let leaf_params = compute_leaf_params(metadata.circuit_id, base_vk.clone(), leaf_vk); diff --git a/prover/witness_generator/src/node_aggregation.rs b/prover/witness_generator/src/node_aggregation.rs index 324b05ace8aa..58508c768bfc 100644 --- a/prover/witness_generator/src/node_aggregation.rs +++ b/prover/witness_generator/src/node_aggregation.rs @@ -259,6 +259,7 @@ pub async fn prepare_job( ); } FriProofWrapper::Recursive(recursive_proof) => recursive_proofs.push(recursive_proof), + FriProofWrapper::Eip4844(_) => anyhow::bail!("EIP 4844 should not be run as a node."), } } diff --git a/prover/witness_generator/src/scheduler.rs b/prover/witness_generator/src/scheduler.rs index 98fe8338f85f..55ffd4aa8a52 100644 --- a/prover/witness_generator/src/scheduler.rs +++ b/prover/witness_generator/src/scheduler.rs @@ -250,6 +250,9 @@ pub async fn prepare_job( FriProofWrapper::Recursive(recursive_proof) => { recursive_proofs.push(recursive_proof.into_inner()) } + FriProofWrapper::Eip4844(_) => { + anyhow::bail!("EIP 4844 should not be run as a scheduler") + } } } diff --git a/prover/witness_vector_generator/src/generator.rs b/prover/witness_vector_generator/src/generator.rs index af400042a9d3..3b49433dfdde 100644 --- a/prover/witness_vector_generator/src/generator.rs +++ b/prover/witness_vector_generator/src/generator.rs @@ -66,6 +66,10 @@ impl WitnessVectorGenerator { CircuitWrapper::Recursive(recursive_circuit) => { recursive_circuit.synthesis::(&finalization_hints) } + CircuitWrapper::Eip4844(_) => { + // TODO: figure out if we support 4844 circuit as GPU. + todo!() + } }; Ok(WitnessVectorArtifacts::new(cs.witness.unwrap(), job)) } From 9e9628195216558b6979f8bbe59a788c499985dc Mon Sep 17 00:00:00 2001 From: Lech <88630083+Artemka374@users.noreply.github.com> Date: Wed, 21 Feb 2024 12:56:10 +0200 Subject: [PATCH 013/106] fix: Return back sepolia.json (#1165) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Return back token config for sepolia ## Why ❔ It was accidentally removed ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- etc/tokens/sepolia.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/etc/tokens/sepolia.json b/etc/tokens/sepolia.json index e69de29bb2d1..899571df9e5a 100644 --- a/etc/tokens/sepolia.json +++ b/etc/tokens/sepolia.json @@ -0,0 +1,14 @@ +[ + { + "name": "DAI", + "symbol": "DAI", + "decimals": 18, + "address": "0x35EfF6eA96571ff475136117FdD92A9ba25b1f37" + }, + { + "name": "Wrapped Ether", + "symbol": "WETH", + "decimals": 18, + "address": "0x7b79995e5f793A07Bc00c21412e50Ecae098E7f9" + } +] From 0dda7cc6f9559503f3801e6d0b9d5ba9649815bd Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Wed, 21 Feb 2024 13:58:22 +0200 Subject: [PATCH 014/106] perf(db): Improve `get_logs_by_tx_hashes` query (#1171) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Removes ordering by `tx_index_in_block` ## Why ❔ Ordering by `tx_index_in_block` is not needed, (`miniblock_number `, `event_index_in_block`) is enough. We currently have an index on (`miniblock_number `, `tx_index_in_block`, `event_index_in_block`) and it can be removed after this PR is applied. ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- ...4e13d46b5ea54a144ec2345a76b865c85f84b.json | 28 ------------------- ...8fc90b18155e3435f58d9888fa50d92042f7.json} | 4 +-- core/lib/dal/src/events_dal.rs | 1 - 3 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json rename core/lib/dal/.sqlx/{query-8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed.json => query-3ba9bc85e3e286aadef8aad27eb38fc90b18155e3435f58d9888fa50d92042f7.json} (91%) diff --git a/core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json b/core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json deleted file mode 100644 index d28ef3efdc2e..000000000000 --- a/core/lib/dal/.sqlx/query-24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n initiator_address,\n MAX(nonce)\n FROM\n transactions\n WHERE\n initiator_address = ANY ($1)\n AND is_priority = FALSE\n AND (\n miniblock_number IS NOT NULL\n OR error IS NULL\n )\n GROUP BY\n initiator_address\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "initiator_address", - "type_info": "Bytea" - }, - { - "ordinal": 1, - "name": "max", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "ByteaArray" - ] - }, - "nullable": [ - false, - null - ] - }, - "hash": "24fa393b7c3a0178806a223ad474e13d46b5ea54a144ec2345a76b865c85f84b" -} diff --git a/core/lib/dal/.sqlx/query-8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed.json b/core/lib/dal/.sqlx/query-3ba9bc85e3e286aadef8aad27eb38fc90b18155e3435f58d9888fa50d92042f7.json similarity index 91% rename from core/lib/dal/.sqlx/query-8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed.json rename to core/lib/dal/.sqlx/query-3ba9bc85e3e286aadef8aad27eb38fc90b18155e3435f58d9888fa50d92042f7.json index ba3ee8a51d7b..221e04e0c717 100644 --- a/core/lib/dal/.sqlx/query-8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed.json +++ b/core/lib/dal/.sqlx/query-3ba9bc85e3e286aadef8aad27eb38fc90b18155e3435f58d9888fa50d92042f7.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n address,\n topic1,\n topic2,\n topic3,\n topic4,\n value,\n NULL::bytea AS \"block_hash\",\n NULL::BIGINT AS \"l1_batch_number?\",\n miniblock_number,\n tx_hash,\n tx_index_in_block,\n event_index_in_block,\n event_index_in_tx\n FROM\n events\n WHERE\n tx_hash = ANY ($1)\n ORDER BY\n miniblock_number ASC,\n tx_index_in_block ASC,\n event_index_in_block ASC\n ", + "query": "\n SELECT\n address,\n topic1,\n topic2,\n topic3,\n topic4,\n value,\n NULL::bytea AS \"block_hash\",\n NULL::BIGINT AS \"l1_batch_number?\",\n miniblock_number,\n tx_hash,\n tx_index_in_block,\n event_index_in_block,\n event_index_in_tx\n FROM\n events\n WHERE\n tx_hash = ANY ($1)\n ORDER BY\n miniblock_number ASC,\n event_index_in_block ASC\n ", "describe": { "columns": [ { @@ -90,5 +90,5 @@ false ] }, - "hash": "8cd11172fc47ff8d37c22ba4163cd2d08a708c3af75fee57379a709baa3c4bed" + "hash": "3ba9bc85e3e286aadef8aad27eb38fc90b18155e3435f58d9888fa50d92042f7" } diff --git a/core/lib/dal/src/events_dal.rs b/core/lib/dal/src/events_dal.rs index 90405028e428..fa44b187cace 100644 --- a/core/lib/dal/src/events_dal.rs +++ b/core/lib/dal/src/events_dal.rs @@ -219,7 +219,6 @@ impl EventsDal<'_, '_> { tx_hash = ANY ($1) ORDER BY miniblock_number ASC, - tx_index_in_block ASC, event_index_in_block ASC "#, &hashes[..], From add2321e9f039afbbb4e90d1fb0269053608af9e Mon Sep 17 00:00:00 2001 From: Danil Date: Wed, 21 Feb 2024 13:14:07 +0100 Subject: [PATCH 015/106] fix(zk_stack): fix docker compose and prover setup (#1164) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --------- Signed-off-by: Danil --- infrastructure/zk/src/hyperchain_wizard.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/infrastructure/zk/src/hyperchain_wizard.ts b/infrastructure/zk/src/hyperchain_wizard.ts index c80cdf4a76c2..204557ba9b83 100644 --- a/infrastructure/zk/src/hyperchain_wizard.ts +++ b/infrastructure/zk/src/hyperchain_wizard.ts @@ -139,7 +139,7 @@ async function setHyperchainMetadata() { const results: any = await enquirer.prompt(questions); let deployer, governor, ethOperator, feeReceiver: ethers.Wallet | undefined; - let feeReceiverAddress, l1Rpc, l1Id, databaseUrl; + let feeReceiverAddress, l1Rpc, l1Id, databaseUrl, databaseProverUrl; if (results.l1Chain !== BaseNetwork.LOCALHOST || results.l1Chain !== BaseNetwork.LOCALHOST_CUSTOM) { // If it's not a localhost chain, we need to remove the CONTRACTS_CREATE2_FACTORY_ADDR from the .env file and use default value. @@ -170,13 +170,22 @@ async function setHyperchainMetadata() { connectionsQuestions.push({ message: - 'What is the connection URL for your Postgress 14 database (format is postgres://:@:/)?', + 'What is the connection URL for your Postgress 14 main database (format is postgres://:@:/)?', name: 'dbUrl', type: 'input', initial: 'postgres://postgres@localhost/zksync_local', required: true }); + connectionsQuestions.push({ + message: + 'What is the connection URL for your Postgress 14 prover database (format is postgres://:@:/)?', + name: 'dbProverUrl', + type: 'input', + initial: 'postgres://postgres@localhost/prover_local', + required: true + }); + connectionsQuestions.push({ message: 'Do you want to generate new addresses/keys for the Deployer, Governor and ETh Operator, or insert your own keys?', @@ -189,6 +198,7 @@ async function setHyperchainMetadata() { l1Rpc = connectionsResults.l1Rpc; databaseUrl = connectionsResults.dbUrl; + databaseProverUrl = connectionsResults.dbProverUrl; if (results.l1Chain === BaseNetwork.LOCALHOST_CUSTOM) { l1Id = connectionsResults.l1NetworkId; @@ -259,10 +269,12 @@ async function setHyperchainMetadata() { feeReceiverAddress = keyResults.feeReceiver; } } else { - l1Rpc = 'http://localhost:8545'; + l1Rpc = 'http://127.0.0.1:8545'; l1Id = 9; - databaseUrl = 'postgres://postgres:notsecurepassword@localhost:5432/zksync_local'; + databaseUrl = 'postgres://postgres:notsecurepassword@127.0.0.1:5432/zksync_local'; wrapEnvModify('DATABASE_URL', databaseUrl); + databaseProverUrl = 'postgres://postgres:notsecurepassword@127.0.0.1:5432/prover_local'; + wrapEnvModify('DATABASE_PROVER_URL', databaseProverUrl); const richWalletsRaw = await fetch( 'https://raw.githubusercontent.com/matter-labs/local-setup/main/rich-wallets.json' From 72c60bdaf242576a1a3e9b068e489f2c601d2d96 Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Wed, 21 Feb 2024 16:31:29 +0200 Subject: [PATCH 016/106] fix(contract-verifier): allow other zksolc settings (#1174) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Contract verifier allows any fields in standard json input settings and passes them to zksolc. ## Why ❔ New fields are added to settings from time to time, contract verifier should just accept them and pass to zksolc. ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- core/bin/contract-verifier/src/verifier.rs | 9 ++++-- .../bin/contract-verifier/src/zksolc_utils.rs | 30 ++++--------------- docker/contract-verifier/Dockerfile | 7 +++++ 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/core/bin/contract-verifier/src/verifier.rs b/core/bin/contract-verifier/src/verifier.rs index ac749dfe4b22..f75d69bbc342 100644 --- a/core/bin/contract-verifier/src/verifier.rs +++ b/core/bin/contract-verifier/src/verifier.rs @@ -305,13 +305,16 @@ impl ContractVerifier { enabled: request.req.optimization_used, mode: request.req.optimizer_mode.and_then(|s| s.chars().next()), }; + let optimizer_value = serde_json::to_value(optimizer).unwrap(); let settings = Settings { - libraries: None, output_selection: Some(default_output_selection), - optimizer, is_system: request.req.is_system, - metadata: None, + other: serde_json::Value::Object( + vec![("optimizer".to_string(), optimizer_value)] + .into_iter() + .collect(), + ), }; Ok(ZkSolcInput::StandardJson(StandardJson { diff --git a/core/bin/contract-verifier/src/zksolc_utils.rs b/core/bin/contract-verifier/src/zksolc_utils.rs index 560bacb809f9..db1fcf0a96d7 100644 --- a/core/bin/contract-verifier/src/zksolc_utils.rs +++ b/core/bin/contract-verifier/src/zksolc_utils.rs @@ -34,38 +34,20 @@ pub struct Source { pub content: String, } -#[derive(Debug, Serialize, Deserialize)] -pub enum MetadataHash { - /// Do not include bytecode hash. - #[serde(rename = "none")] - None, -} - -#[derive(Debug, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Metadata { - /// The bytecode hash mode. - #[serde(skip_serializing_if = "Option::is_none")] - pub bytecode_hash: Option, -} - +/// Compiler settings. +/// There are fields like `output_selection` and `is_system` which are accessed by contract verifier explicitly. +/// Other fields are accumulated in `other`, this way every field that was in the original request will be passed to a compiler. #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Settings { - /// The linker library addresses. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub libraries: Option>>, /// The output selection filters. pub output_selection: Option, - /// The optimizer settings. - #[serde(default)] - pub optimizer: Optimizer, - /// The metadata settings. - #[serde(skip_serializing_if = "Option::is_none")] - pub metadata: Option, /// Flag for system compilation mode. #[serde(default)] pub is_system: bool, + /// Other fields. + #[serde(flatten)] + pub other: serde_json::Value, } #[derive(Debug, Serialize, Deserialize)] diff --git a/docker/contract-verifier/Dockerfile b/docker/contract-verifier/Dockerfile index 2fd6a7323619..e7991a950bef 100644 --- a/docker/contract-verifier/Dockerfile +++ b/docker/contract-verifier/Dockerfile @@ -28,6 +28,13 @@ RUN for VERSION in $(seq -f "v1.3.%g" 9 17); do \ chmod +x /etc/zkvyper-bin/$VERSION/zkvyper; \ done +# install zkvyper 1.4.x +RUN for VERSION in $(seq -f "v1.4.%g" 0 0); do \ + mkdir -p /etc/zkvyper-bin/$VERSION && \ + wget https://github.com/matter-labs/zkvyper-bin/raw/main/linux-amd64/zkvyper-linux-amd64-musl-$VERSION -O /etc/zkvyper-bin/$VERSION/zkvyper && \ + chmod +x /etc/zkvyper-bin/$VERSION/zkvyper; \ + done + # install solc COPY docker/contract-verifier/install-all-solc.sh install-all-solc.sh RUN bash ./install-all-solc.sh From 2a0368b4e0d5ec1c27c4b0b76b7ef83dae2d3bb7 Mon Sep 17 00:00:00 2001 From: Danil Date: Wed, 21 Feb 2024 17:06:40 +0100 Subject: [PATCH 017/106] fix(zk_stack): Use correct owner and db url (#1178) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. Signed-off-by: Danil --- infrastructure/zk/src/hyperchain_wizard.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/infrastructure/zk/src/hyperchain_wizard.ts b/infrastructure/zk/src/hyperchain_wizard.ts index 204557ba9b83..5f206c20452a 100644 --- a/infrastructure/zk/src/hyperchain_wizard.ts +++ b/infrastructure/zk/src/hyperchain_wizard.ts @@ -52,6 +52,7 @@ async function initHyperchain() { const deployL2Weth = Boolean(process.env.DEPLOY_L2_WETH || false); const deployTestTokens = Boolean(process.env.DEPLOY_TEST_TOKENS || false); + const governorAdrress = ethers.utils.computeAddress(governorPrivateKey!); const initArgs: InitArgs = { skipSubmodulesCheckout: false, skipEnvSetup: true, @@ -65,7 +66,7 @@ async function initHyperchain() { deploy: deployTestTokens, args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] }, - deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey] + deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey, '--owner-address', governorAdrress] }; await init(initArgs); @@ -173,7 +174,7 @@ async function setHyperchainMetadata() { 'What is the connection URL for your Postgress 14 main database (format is postgres://:@:/)?', name: 'dbUrl', type: 'input', - initial: 'postgres://postgres@localhost/zksync_local', + initial: 'postgres://postgres:notsecurepassword@127.0.0.1:5432/zksync_local', required: true }); @@ -182,7 +183,7 @@ async function setHyperchainMetadata() { 'What is the connection URL for your Postgress 14 prover database (format is postgres://:@:/)?', name: 'dbProverUrl', type: 'input', - initial: 'postgres://postgres@localhost/prover_local', + initial: 'postgres://postgres:notsecurepassword@127.0.0.1:5432/prover_local', required: true }); From cad727893b68a34d0d622e5f0349264119b207e8 Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:31:59 +0100 Subject: [PATCH 018/106] feat(prover): Added --recompute-if-missing option to key generator (#1151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Added recompute-if-missing option to key generator * Updated setup.sh to use this option. ## Why ❔ * This allows to quickly recompute the setup keys that were missing, making it easier to run local provers. --- prover/setup.sh | 31 ++----------------- .../src/keystore.rs | 10 +++++- .../src/main.rs | 9 ++++-- .../src/setup_data_generator.rs | 16 ++++++++-- 4 files changed, 32 insertions(+), 34 deletions(-) diff --git a/prover/setup.sh b/prover/setup.sh index 0f2b2d3301f6..e755f5ae433a 100755 --- a/prover/setup.sh +++ b/prover/setup.sh @@ -23,32 +23,5 @@ rm ../etc/env/base/fri_proof_compressor.toml.backup zk config compile dev - -SHOULD_GENERATE_KEYS=false - -for i in {1..13} -do - if ! [ -f vk_setup_data_generator_server_fri/data/setup_basic_${i}_data.bin ]; then - SHOULD_GENERATE_KEYS=true - fi -done - -if ! [ -f vk_setup_data_generator_server_fri/data/setup_scheduler_data.bin ]; then - SHOULD_GENERATE_KEYS=true -fi - -if ! [ -f vk_setup_data_generator_server_fri/data/setup_node_data.bin ]; then - SHOULD_GENERATE_KEYS=true -fi - -for i in {3..15} -do - if ! [ -f vk_setup_data_generator_server_fri/data/setup_leaf_${i}_data.bin ]; then - SHOULD_GENERATE_KEYS=true - fi -done - - -if [ "$SHOULD_GENERATE_KEYS" = "true" ]; then - zk f cargo run $GPU_FLAG --release --bin key_generator -- $GENERATE_SK_COMMAND all -fi \ No newline at end of file +# Update setup keys (only if they are not present) +zk f cargo run $GPU_FLAG --release --bin key_generator -- $GENERATE_SK_COMMAND all --recompute-if-missing diff --git a/prover/vk_setup_data_generator_server_fri/src/keystore.rs b/prover/vk_setup_data_generator_server_fri/src/keystore.rs index dcbb7af96038..ccb729a1cf1c 100644 --- a/prover/vk_setup_data_generator_server_fri/src/keystore.rs +++ b/prover/vk_setup_data_generator_server_fri/src/keystore.rs @@ -1,4 +1,8 @@ -use std::{fs, fs::File, io::Read}; +use std::{ + fs::{self, File}, + io::Read, + path::Path, +}; use anyhow::Context as _; use circuit_definitions::{ @@ -293,6 +297,10 @@ impl Keystore { }) } + pub fn is_setup_data_present(&self, key: &ProverServiceDataKey) -> bool { + Path::new(&self.get_file_path(key.clone(), ProverServiceDataType::SetupData)).exists() + } + pub fn save_setup_data_for_circuit_type( &self, key: ProverServiceDataKey, diff --git a/prover/vk_setup_data_generator_server_fri/src/main.rs b/prover/vk_setup_data_generator_server_fri/src/main.rs index dadbd4b72f9e..bf5f4a86bb63 100644 --- a/prover/vk_setup_data_generator_server_fri/src/main.rs +++ b/prover/vk_setup_data_generator_server_fri/src/main.rs @@ -104,6 +104,11 @@ struct GeneratorOptions { #[arg(long, default_value = "false")] dry_run: bool, + /// If true, then generate the setup key, only if it is missing. + // Warning: this doesn't check the correctness of the existing file. + #[arg(long, default_value = "false")] + recompute_if_missing: bool, + #[arg(long)] path: Option, @@ -170,7 +175,7 @@ fn generate_setup_keys( ) -> anyhow::Result<()> { let circuit_type = match options.circuits_type { CircuitSelector::All => { - let digests = generator.generate_all(options.dry_run)?; + let digests = generator.generate_all(options.dry_run, options.recompute_if_missing)?; tracing::info!("Setup keys md5(s):"); print_stats(digests)?; return Ok(()); @@ -189,7 +194,7 @@ fn generate_setup_keys( }; let digest = generator - .generate_and_write_setup_data(circuit_type, options.dry_run) + .generate_and_write_setup_data(circuit_type, options.dry_run, options.recompute_if_missing) .context("generate_setup_data()")?; tracing::info!("digest: {:?}", digest); Ok(()) diff --git a/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs b/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs index 371bfbe0327b..3b2724251846 100644 --- a/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs +++ b/prover/vk_setup_data_generator_server_fri/src/setup_data_generator.rs @@ -85,7 +85,15 @@ pub trait SetupDataGenerator { &self, circuit: ProverServiceDataKey, dry_run: bool, + recompute_if_missing: bool, ) -> anyhow::Result { + if recompute_if_missing && self.keystore().is_setup_data_present(&circuit) { + tracing::info!( + "Skipping setup computation for {:?} as file is already present.", + circuit.name(), + ); + return Ok("Skipped".to_string()); + } let serialized = self.generate_setup_data(circuit.clone())?; let digest = md5::compute(&serialized); @@ -100,12 +108,16 @@ pub trait SetupDataGenerator { } /// Generate all setup keys for boojum circuits. - fn generate_all(&self, dry_run: bool) -> anyhow::Result> { + fn generate_all( + &self, + dry_run: bool, + recompute_if_missing: bool, + ) -> anyhow::Result> { Ok(ProverServiceDataKey::all_boojum() .iter() .map(|circuit| { let digest = self - .generate_and_write_setup_data(circuit.clone(), dry_run) + .generate_and_write_setup_data(circuit.clone(), dry_run, recompute_if_missing) .context(circuit.name()) .unwrap(); (circuit.name(), digest) From d8894fea1e439a1d3945b79b378ee83df7d45cf6 Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Wed, 21 Feb 2024 18:32:31 +0100 Subject: [PATCH 019/106] chore(prover): Remove obsolete files (#1148) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Removing data files that are no longer needed ## Why ❔ * verification_leaf_1 - is now called 'verification_scheduler' * verification_leaf_2 - is now called "verification_node' * witness_arttifacts.json was used to generate a set of basic circuits, but now we depend on the test_harness to get this list * scheduler.bin was used in the past to generate snark wrapper verification key - but since then we moved to verification key generation that doesn't need a real proof anymore. * --- .../data/scheduler_proof.bin | Bin 732737 -> 0 bytes .../data/verification_leaf_1_key.json | 270 ------------------ .../data/verification_leaf_2_key.json | 262 ----------------- .../data/witness_artifacts.json | 1 - 4 files changed, 533 deletions(-) delete mode 100644 prover/vk_setup_data_generator_server_fri/data/scheduler_proof.bin delete mode 100644 prover/vk_setup_data_generator_server_fri/data/verification_leaf_1_key.json delete mode 100644 prover/vk_setup_data_generator_server_fri/data/verification_leaf_2_key.json delete mode 100644 prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json diff --git a/prover/vk_setup_data_generator_server_fri/data/scheduler_proof.bin b/prover/vk_setup_data_generator_server_fri/data/scheduler_proof.bin deleted file mode 100644 index e83bf197df308086db18f08b5aed9be910da69a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 732737 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
  • 1^vR(;!_uFAJ}2`LLM`6>a;k33@kUS` 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 U%k4HjB&7hsHknyywHQ}0hQ*5q zF{C*bY6j~ZYh!%*me5Pm{L=8q%4a9GHztuCRmrgiS~75@)aKdDtSE8t4f!<`P-@8d zCI^)teRt}MFvH9)Sby>_BynsfQlCg%^69QP>c-PD#9GCSo@v7o&roBgT$7I3411TukN8ym(ci%L}#j_um& za%(keYPl{g z>QwtA!zJwP`J(V9_Qw0rONpqCDBkH_kh=+o38>(z6CEWH<(PzIpIJVggX&L=OwR+z zN~bQv_tFim{xR#KHE{B^5rz!KMK`3M?@&aU7 ze9FasoRqkwGp!I$wZmo(e8PHxuf@WGMt0uTDA%`}{$zGhjsQnYSx{PgC!$47pi(^aV|mQvK$&qL7knnqidKpqj<2uf_*ciT)vxAk__rZP&JuP-G>-umOYSvq>vriGf`s^(vOlXD zC3le`pP1vc7By>1B5Y-#0K>&EN-e06rGt^Uk55aW>BA#3@t{Z>1=xuuDY9;g7E+9k zVB{`x-8P|BV1OQ^(<(R|i}A=Bh<}XGw&Vb4Og5L+pW8XH$pQ{j2>%o^KHU5C|bcQpPX~imp>v@!5BdL!GS_4%IHIe{AT5X~@lfOAg zM0dvX0jN68Y&e0py;r-y{Mghlf9G&FM{3?Vq*^$62LCpjt!kMZC1K*oZ=L0zSq1kQ znNepH^Sgza80;*MDdTWtv0?MJbTUkpSU(^1O^qO|)zSDT;!}Q!oG*YslAMTc7V(** zmJE-yTwoG2W1HDv~-D3tNak|lvzy+RPzWOJT!Cuk9WN!_|&VVZ?_7;1Q z^AAz=_Q(ZIe5luV1__!G%kasYus?9O{Zc1btSGaT#dIARoK>-=;zXT@1i)h2(Z#oGDWZnglm4Jj5ps%UknR#n7W62Yw4J<;mYkdTh zo6r=?Xoe&Bt4AKB8CY}W$-SgDrw2(=Y$a>BJkd&`AvvmJBto=SaDJNqb|as~jT#v+ z-C3v`)**z*h2yVS1qoa{giR=-v(Ne}3wBzN(xcW;e9=w3Lud6Qj0>9!`mhHacK=N| zymfd2#4Nir2|o#rXPDaIN%JM&%`Pj+VeTsV!9l^T%@LpBhWj$ z^b?hTBK&DAzX!eec70E+_SwNR0WPG2lGw=7OUJI{}3+-l`TeAas zLDltqeP+z6I*Qm3DCx(g#|yc0u2R8-p2IOkQ5_#-lkWIHl;y!8-&?2F&5c}@s{orU z^X!($5ocdLH*qxK%!-$tuG-@Urhh6OE;)Qy9zU&Y_VUZi?4RIP>5B`QgO=Lt6!aFx z#0U<+U{WF~O|w~;-#zG0eX07QKKbo#22Kvk`d=*CKp(;I&RZPvt#RD4Ic92hfp5F$ zkptZ`*(Icd`cO`2_{c5U*HLq`om@OukPB~NAlLlD{El9_N|LT*k zogAMp45C^o*X^YZ@*WhSbbkaOWV6tx9;-;qVQ>C(E5MQ4z%svLZ`Ke(NMEK;0qPMK zMudMh=4g3j*jxEZ0)vrUTA6vkrPl*BUz+C|OSkN;d z(ZGxvaM7{}7+IvnE4qjZK(wfP{jx+UV%ITiE$R=}(9#-gU7uW4x!ktvxo|p;4*?i0 zb6^!Ig~|7<2R0jT0q%-}Zy1-;Z;#%5VkXY{?*#XVKTGa-fIUh0eD%t=L_sqbON0G6Mg+e*bj$DlLpnH_+us8!CD9tOqu|s$W~~4_A6l@ z4&wBQ2ra(zOo!GVb0*T%nxuAb?Wpem-sxTbP|rwncFhy?KonV3hj<^TTXXs}^@HYx zrr>L_$0&gRZBWt34=QBYdFFKv3egJGbjg8ceM%*Iqi%c=Mt%_dLrKy z5o>0@$G;+2Fc@5z;9ws-r+HNpjJPujfT0=4&UfkCdWQ4m5JzM$J0DxZdD$pQFYq$C z<$sYTiz?7__8hgXXoEu2d&7kBRHqDkKe_D@2qi|_mY)qp_!k#R_yguKIF08Dz6ez;<4>ndu>wS&dt+0cd|2!v9XkqrTg@y3AG3%H zzG+OF%Fsbj$#-r|1l@?=)TsnmT&1%*JlwU1)dA&OKGsw{@IWlF*qj_LU^wMNK&ORs zfi=zfi$ydy%?<`UD>A}Auq{>ITDoFeN(Mi*>n>v{&gr*AAG|U_`_igH+kqk#%|oS7 zIP&YC=dP}RFplqJYA(m){`su@BO*%quI?%+k{Mj3p6CoG#}Uy4lX{nQ{@I`8zXEr^ zTy7a~9;yzTp4ZLsh#XQ7jRVZR1c(HL2^#@Zk$4_vxs}OAX0g9N;F6$_>v>@^GOJii z_GWJXC5{s0u*wPC7=8Q_44P;YO@$~cM4<0wYr zyE^W)^hTm3i@_t|GWqvQA3f8=mLLp%_vk<8nj4gJF0x4JSDkcm@m8*(t({?xvOl$O zM*0+sKBu@vTI#r?3-jOb$}2hdO9YBMZHX0AO_@6oVvmwP#WT)9@9w*QAX=VAg%ZcZ z7EN{}LAeAx!-J{f8R3m~q##g?p^FoMSW>a7eh@DW3>}nC-Mp8liW;Y;WQmN_Sl$fD z=3r-#3agY*EC!ZbgpL8t@zQ zPzKKM;%>XK(eV(+j5J`l4cOLa6qd|vtg!qSEx^oQSJUG;Zs!DEAzS>^V z3Ego)eYfg-jX=+-uTR){a7-DS*m6pExcH4i$Ru+h-3jo$y)M1GmLfTtPNW-i_@IC) zet>e;*Ol*d?h{5u5hIa8QRTPDlm{1%1Z>6;LRa<*O9!60Ev0)S`B3gQ9HMz>37ORK zt@t#>C53=?|K;mLr8#jog|Dk?4%vi0ac}!e{JY~X;MUs34^gOULAQS2t_ai!B0DB( zPa0~iDt`IG;fXi@dygL8_qRqYS=;^4;1jOZ3PEd<sP-Q5im z|GS?!=;?P+UCy=i+T-HEd48ym*PStGT`+{L)fqMl4v$sLPa&^F)C!1s=$k{cEZeq(yk(~on#`2+ciLc%7;O7NRlwmK{n#knyZ@Yle6n&Y0_=*;{(gj_(u@WOLO5)f~NV}9}s zA`Ph#wuYF!bxl1mX_ki^Qpu_ec9qdvEp zTx$tvpY39&^+6P#!dYv!UP2G#1(+FiZmbIZbMEf|qrt8qJ-4ac8Bmu|%S3HJjGPaC z2`2M&1QCRG!&|F3G=?TZO{G`#GD9Va6H2gGVpi-{8V*3%^&-)O1prlSd_uCs`OS&1^MfW3&;uZ8}+X=$hGVx#yzwqjPJ@AL9EUAqk~g;W=*x z-4EUijlIeRLOAEa-OtGdWB5_E)N5Eh*A;u+3h{ZO`zToC$wSwK3V?1U6chX@8Kdy}=v2n~mH zgLgsaoK+$pUa$mcoG`FMZ?r|U`<1aOP{2^T&HwJh&T^)-9_kYXdJFsJ z?sQGLUC1_Bm7-`hpk|sjB@8WS9$!D}j$5fCRkyh4&?K4V#`RJQgN|KjMq1dpt7!90 zh>*6K9(zx+A*qA@bG8Hdv_brV?qhL?KBX1I?D{*l8A%1KHuZtJi7I8e!v1I;r}zX< z0D6sL`GO75vr0D#G`Hl`=;O2?@wX?Cz-LKlE{&4LY=s;C8ILEjDcZEF(cD!p0xq-x z%?75$HRzgR*pth$hU6cSXKbiFsxR5rY3obUhBrYoEP23 zYWuLkk%A8R{ouU(kepSyZgYY*jd5^4j<~*@pNebw2q30@g&+w5@j;r5C2PW4D1Rsc7LRUeE6W|q zFr#flRNUI72X_Btt3oHuT=3l+WB2Ls>f!Idm#$L-O%_9>)Fu| zcmYw1K&r^!eB~s94rz_!9Bz5(sqwWwip)(VPXH- zK0@l`{~F#oL=JU%f|}vY&ge+ivENAiASw2a-#QPqa_IP?LIv%iX z=#jn%br{`xBH&nlZEQP(HJ#zT2f>l_>++)6mFvBBu1$OGrXPzbnd;9o^^v+tAmbI^ z0uO*5PO1)U@?6mY<$LpnVoEidU?FHEg>xMsja=r)%iVptHeu--xJj=4ni$?G&{&-+SSqK>mRtcb*v|F+M5}I2=<((%o7Kdf zgc7u=HPpHYQY<&*#>?7dg3qAxh(q_d`a?A`G1Dj^c=7)1!$kyK;p4Wm$YpBoDiB;m zzJqu#Te^5=uo287L2mt9Nr3n=;gSJ^VEmG5lFC!wis{JyItaVkr*uS@fZQ>|>Zeqb zUZbk>3Oto!q{}gJ;bQn-U*P*tILGmn+cMH>it!>rD_+Ab9gg;;8O@nm93$PCjc~O0 zwl%uZ(1ot{w|D+UkfB-ks9=Mb+E;UycI#fMT2jZKKkp5#!fZ``p-~wN}=R!3B}xyh#>j7H5i?KO7DN%5X47W^|%0P z1K;i-#g@P_jt1z7p;6VYT{kxV)k=x^;)Qb=sRDF&{Qq!uPHlp1y%sLpwr$(CZQHhO z+qSxFS9RI8ZS(A#J{R9lSQ%?RGnsEPl4~^RYt7QK=Em7yVCG;oJ1XSp`rZ5{D2 z_g-bX4RcuVzMS|i&!t$nANqQVnxsq^s|R6m513c=6$A|f%3ZY>cW3j>JCLjdK%fF= zX$+k8TvRPVlM=uGjv7Pj;n$U%W9WaClb|_vAL0T-R|e*`|ChC)aMOfk=u-@XQwDINtV zkbPtFE?K=P_SynRy~baN0I$DIoW|Fqf$>D^TbCZahT$|j(mi~#b7{QJr;g`#nsyZk zn2XErS8kY*!0U>hdt!0@x1OB+DijdA#p$xexLozR6-Dhh2*;IzB3N+w00fz%7kC@; zQ{RTvDgww!2bcAJ_12!ngAcz<&o2g>!vFM6)H_LM(_%w3iyUn|ri~%aL~B#_Y0$!0 z%@tRV{;Q6_Ny@CpRp2K9cV)gP!ve&4rv2vvQU=(Js+ueF*U?DDB@ z{l!|taTFOvoR1o>%J{MkLh)DXCa!>PMTfSmW=kY~&A`N?Hi9COlIj9)KZZ{M=`L{O zA2+P9GLVB*B9qa8OkOxXH-KfPTE zKq%$(`qce!5@UC@BH}Ae*nDaG<@Hyf2S}E+MOD@)J6?dD%59=@Tn|+47BA0ipJAR| zmi&~cs+n>w#QhWxnCn&w$mj$i{+S+A-al>_&Aihf)Bq2#Gu9y<_ZWufVx$JovS7pQ z7RWFGy zEYO&CtZ&IUFlq~nmcb1f`J01$WlpZ=cnGvIq;ef!<-KM)w0tNkf!+yN@jJ~^#~JSa z&ao5~IH;|5Lurs>+0Pm8DN0!j!pgq~)n*bZsWh?sU%c>qfQ-dktxAc0EnQ($?tzBU zCttX*SQJ{-y5^n*;1F^;?=@wKnRf+L=%rXfA|D~b19EdH)t29Bh>9rBcP+4PG7*(_ z4x3S!4kkXF|Fn7y5`%qUtEi_GOxDJ88YzL+{RPN}NMwIGCM_+5K^8}q5J2?>uq6i2 zl>s#z4G#M^Z)ksEvIn<)zDXkR1pM$e<+ z*MTVO{6kO%cW8_}AdDVYgFVE0HT>@!h)TMMpe7EoF|BLn>hCZl^+@=ncBwx1RgIW0 z(ggQj!-wbx1O?$c>>u<0h1uq|Fb{xC_|3IiVNy|vUihN;^S|?k^l?1lxrP_y{azD* z>!BUDt14BnhpcAHi1vw;Vf+%q1WI4(7XiE#X~f=thg%|j9+u8Csh*=tEaf^ZMB%o| zAE$l3aK3R~nZDBkQDpj{n9?dxcU$;fFhd(3EuHw&vHK~;y3ZH<5QU~W8O>pDf*Lxy zwvo19bCHi-YS^CwN#?P^x#@098RKw_bID7sDMFa%QVI_mLfY5A=O@ioO`SY>^hk@O z2zZw%+_cAk;;oPElzln(&#yFd7u5U`CS0yloC=jVe@oBj{Fb5Eqg!9W%qMrH7p*d> zUH!=8;C0#aT`9% zBQKFYDus}Em680=_W<6*7z&&mcmi>oOWe`|TwulEB{7P(YvA8$z|YCb^p#e~D@Oa& zU}3L;qa_$(eneFsu32t_Kn_86#o%1@rs9J;7*S@Bf53o9;InaK3o?DZw!Wd3xA-U5 z<`@rnGPHy9hHkh!I$!Jwt$0^8V!D=ON2WdLBWKYV{vLlHeGueh2)|TXzK%PE(sx*P zeq?W-2zm7qm*Qf}vF7KkNU$C>xCDF(qitSt_eNdU?o}J%GW>y1taNc zOcKGPoIsfR0_b}{r#stQnBb77VLnik&Rtb?uJF4$ZYC_78 z8h;d9MQE9vw@8OPw%o6q-&Vxf858{9^@f=B5!A>f6f=Sk^3AE1q8 zZp%~kyf*o@29RiCZP<aV7DU4sHN>l-6SiV+U(m#h!;O?Q&Aq? z$iuQ}}LYf`RY7=or4u;?n;*U;3RistQ4TwQVB{+sh#-0p5GQt`YO zXwf}55Ce^u37~uRxwV>h4( z^C$5-Jf;OFOP1yYI2xn#^~5Wk#L#ca9f@;JR9iak^R^g1;mr?{8U_%U(7%#69_G0pKO7%ar+i1{@}+80I>S$afPe2SmAJrF205>ct&sgoVyOQO1% z6t|FwyFrl=nv@niE!MFg{toEMC(wJsGqmVD2{NwRI0d4JsD4;du${FyQu3}ky$bN- z?(Q`o6pmm+5J(Mai*`1-9fQDA;$HkwaGvEzm-pFc$TIAmZllt_I$>g$Wbb{>L3Y$BVEvhT=j`cn@k#n*)n^>oSN z4n#IPQX!QlO1ns93Um`q;j;d?7{qpWBe$=ro;8L2Zqe&qVS%oh;e0H|EvpIv_32Sy z%morg3RQn)Z;pQi!IyK1OCqtGw$~ZzZ_ASY*tlm{$$pT>vfuY?=QIDYFYA4+zGt0! zDdngOVwN!2>4Zz`;u1Io+3l?nUs{G{2H{f}hAtFtYrDBG44@=k^ScqLikZ(==32+%^@!^su>Dh=}F_A8;H=yT2!~GiGLt)R(IS zF(!DW5$(!AEGX!N-oCcB>1>Y6@P0ZJdxS!Rt?=aMTw4cxU0C~%|0>cqrqcbXb?>H< z&aSf4!*cbJ7l3X%dPbWA%QRry?S*cWB#L%bm@=`Yo7$<(TyN!OYL7D>kKwr&YZ`z? ziYW4TfViF9{7N%wtO!U}u6C?S&H^wm;_Mv1hJ5+|zK{62+^BB~#Aqzwk4G=8?@@P5 zG8o15U7G2$3E^ll<$lx-onLwY`8Y3w9YO_C45mkopm=}>UyU~(o$iE=a;h% zEGc(ja=bn06D+_w82jYk86m(cTz4V{k@f29K-Iljwxj0qsL-2cK5@q~b&WLU92&{x zmI*c%Z|F(2iZ6eUe^M9Dz}^6K&acm*omeamy0&3zJ_%V$njk8z z&#G!~6pL?+L zBeouJ);3QO`8BdhCmK&m0tOl6RPIGZ-sYO;zCne;>->^LD5=~p(Dws4A3z1fNw#^c z?dWfz`4zomUP5Mp!hpe?Nd%z$y{4G~`0-OryZ5K>&A|RN+L}TnALP}9e_@pvt;vO1 z3@O2yY3)go$JwQ=_XF^$l8vi6BGxSeM1N~((ZL%#!7_CuuNUxX?br@8nOHQ-l;|mk zbQ>+Kb$lfAHfmZG*%e{bAk+B6cv7S1{sTTzgtc8ynFVi5u9naS625XboiyQkIYt^$ z*A*YuRXh7H-?oGC3KJcoKGR?So;R|3t1bXzVOfRH#Jd&!y#{CBy!hC2G#wPLo5?1 zH6*d0H?pr1#9JrR6?vZusz!vuVV)gJ_j$NYwN0d6HvV^?Oj6*f|m{XDCg0mary)jJP_PVKDfy?4kPWspC8b2R<;PJ$qP!W>7s4hKo$ zhxR!&H5mb(rQi)KfWF?AdyDdlDy~K)zgyGN$!s)(KBsK~h*Rahr7Nw`4e{gBcvigcY$2`>3Wl=@c%*@8Ca4J< zTFXe{9+7Dq<+{;=|0lvpq(c3>yE=G*6^0%&UHIh&a%!JK^jtobdGV)2hiDGh`;LLX z1Z8E%sbfeN#iw`D@oII*f{{w_!GDGT$DN zArD-!^s%JX+UfbPEs~maMURN7G;8P7p%gGk9}OgG`GS`I6JpJ*A8^ zYM}Ugm%8+3B$E#Iu?#)3Q$PIL9(H*%ke?(X#6tpRiWRHS)aSm6-%vC3-31-nwzI&E zL)k3iMK066311)@8R+{$ax}gm%#TyUe@Qi1OqEc+YX&$!Piyts95Lz{Y14T8c!y{S z%)2&B-u3bW8I^)wV~rc^PGJS`YW_k1`(-RitWj+<6a-a_QoVAvFvgq< zsO9C*FKk{1E$RCs?C30 zrk<0R_>$u0JcgPb`etyJ40-OfaSb&DJLV)`yBJUtPtQqHt(?sw0NK5SCm31Pey|x` zIpbo}3w1$d+ljHANLHWK(mBvT4)b%hCNuwtt={5LHM*3{qZSyRu;nVs>`{z-013lr zka2^sKX_K(;wjgtNLPvCHKsxkcsNjlwtiWl&>y%{bG|eyA`2R_tM(RlyGMPEEgaNZtgpCG@ov5p zc>4|Rg8UHY(=8|}Jx5iXxd~8F3cAR(e1(5*&`y^;rnt?d9r2KMXmcQTOv4I==S~HC z<3QTi0qEg}QHW&S)^W{*M+PJW(u|YobH<5CeI5;BNVB#R#(FRM@*CQxm^KNPokTK+ zKi;*)zhKPO4AO07pK|F*NaOh<8+Eoul70wV;OvqG^9Q?A?L!gny0hEr`QuP)T;)bM zC|p@3y*pex!y?o&BZZALfeqkiV)?-QpuwB|!Hm}$YoEn=hVnRjwv*~(c!C-1fhy~V z`Q(P$+M6jaoh2KIB@b!2W>8reK0S2^52OQk@By{>Y(91nMv!kNRGb>I@7HH1x*Lqj zs`e(!vEj$eZ8+F{2>7kk+_wU9M^6LY^VlEbL0L?kl21FuH_{ZO7B~fe_zYC>5JtGu^8(r5SbN-bVue2 z`W(Tm(TsyZ4>Kgtq+s^Ra(u>eG()YK&w^4e-;P&_vls|t0*@1iRtQhG6RE$1

    p5 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

    ;uTk=qRc^HVwBk+EJm+y_LT&1{ZDl*$ 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

    6w5x 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 diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_1_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_1_key.json deleted file mode 100644 index 228a0e9fe926..000000000000 --- a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_1_key.json +++ /dev/null @@ -1,270 +0,0 @@ -{ - "SchedulerCircuit": { - "fixed_parameters": { - "parameters": { - "num_columns_under_copy_permutation": 130, - "num_witness_columns": 0, - "num_constant_columns": 4, - "max_allowed_constraint_degree": 8 - }, - "lookup_parameters": { - "UseSpecializedColumnsWithTableIdAsConstant": { - "width": 3, - "num_repetitions": 4, - "share_table_id": true - } - }, - "domain_size": 1048576, - "total_tables_len": 132096, - "public_inputs_locations": [ - [ - 0, - 993345 - ], - [ - 1, - 993345 - ], - [ - 2, - 993345 - ], - [ - 3, - 993345 - ] - ], - "extra_constant_polys_for_selectors": 4, - "table_ids_column_idxes": [ - 8 - ], - "quotient_degree": 8, - "selectors_placement": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 1, - "num_constants": 0, - "degree": 7, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "Fork": { - "left": { - "Fork": { - "left": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 4, - "num_constants": 4, - "degree": 3, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "Fork": { - "left": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 5, - "num_constants": 1, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 6, - "num_constants": 0, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - } - } - }, - "right": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 2, - "num_constants": 0, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 7, - "num_constants": 0, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - } - } - } - } - } - } - }, - "right": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 9, - "num_constants": 4, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 0, - "num_constants": 4, - "degree": 1, - "needs_selector": true, - "is_lookup": false - } - } - } - } - } - }, - "right": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 3, - "num_constants": 2, - "degree": 3, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 8, - "num_constants": 0, - "degree": 0, - "needs_selector": true, - "is_lookup": false - } - } - } - } - } - } - } - }, - "fri_lde_factor": 2, - "cap_size": 16 - }, - "setup_merkle_tree_cap": [ - [ - 5188923951567823784, - 1839604164061896861, - 3760614143058722712, - 17614504340708244503 - ], - [ - 7889899638667026800, - 14244435798393850379, - 15230145556400915502, - 12762495992738055897 - ], - [ - 1590798346328722678, - 14143092007536417439, - 10480901561038728792, - 3201431705395147463 - ], - [ - 2780378477031897976, - 11901528146276690135, - 1343277030558816196, - 6658753207411088573 - ], - [ - 11039463659901501365, - 8235548863391687887, - 1033553352576624721, - 12882010447949399432 - ], - [ - 18078277235848158043, - 14794319235551634496, - 13982848369540832169, - 11146980369941489422 - ], - [ - 5423143341883663864, - 15258729611778297770, - 7733187200367671156, - 11434904591161598775 - ], - [ - 10914070908442174902, - 8055525792807466851, - 14391942428843610452, - 11749906933466154458 - ], - [ - 14580351359387308464, - 13254290427053014332, - 7257863927775762043, - 11078203905320069045 - ], - [ - 6123238811378029441, - 11756658038961859601, - 760000874907607862, - 678236515728235822 - ], - [ - 15657816790157674514, - 4104741954972330508, - 4150394799973679527, - 15124992265078810298 - ], - [ - 13825567788010925982, - 636544017935987097, - 2260460249587621344, - 10354042489703999934 - ], - [ - 12710868603685796297, - 91862114057079406, - 5614554900380483346, - 131393259919990755 - ], - [ - 13185811107579017595, - 1006028503100864020, - 2087984259170414019, - 6445764843889735797 - ], - [ - 10414938568348349467, - 15415934042755645234, - 11692038010863343064, - 2402843492027871760 - ], - [ - 17752536940710015241, - 14329244239886245722, - 16349180633511906354, - 2663305413222761702 - ] - ] - } -} \ No newline at end of file diff --git a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_2_key.json b/prover/vk_setup_data_generator_server_fri/data/verification_leaf_2_key.json deleted file mode 100644 index 7865e106454e..000000000000 --- a/prover/vk_setup_data_generator_server_fri/data/verification_leaf_2_key.json +++ /dev/null @@ -1,262 +0,0 @@ -{ - "NodeLayerCircuit": { - "fixed_parameters": { - "parameters": { - "num_columns_under_copy_permutation": 140, - "num_witness_columns": 0, - "num_constant_columns": 4, - "max_allowed_constraint_degree": 8 - }, - "lookup_parameters": "NoLookup", - "domain_size": 1048576, - "total_tables_len": 0, - "public_inputs_locations": [ - [ - 0, - 0 - ], - [ - 1, - 0 - ], - [ - 2, - 0 - ], - [ - 3, - 0 - ] - ], - "extra_constant_polys_for_selectors": 4, - "table_ids_column_idxes": [], - "quotient_degree": 8, - "selectors_placement": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 1, - "num_constants": 0, - "degree": 7, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "Fork": { - "left": { - "Fork": { - "left": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 4, - "num_constants": 4, - "degree": 3, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "Fork": { - "left": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 5, - "num_constants": 1, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 6, - "num_constants": 0, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - } - } - }, - "right": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 2, - "num_constants": 0, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 7, - "num_constants": 0, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - } - } - } - } - } - } - }, - "right": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 9, - "num_constants": 4, - "degree": 2, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 0, - "num_constants": 4, - "degree": 1, - "needs_selector": true, - "is_lookup": false - } - } - } - } - } - }, - "right": { - "Fork": { - "left": { - "GateOnly": { - "gate_idx": 3, - "num_constants": 2, - "degree": 3, - "needs_selector": true, - "is_lookup": false - } - }, - "right": { - "GateOnly": { - "gate_idx": 8, - "num_constants": 0, - "degree": 0, - "needs_selector": true, - "is_lookup": false - } - } - } - } - } - } - } - }, - "fri_lde_factor": 2, - "cap_size": 16 - }, - "setup_merkle_tree_cap": [ - [ - 16110944391299715992, - 6257581196984129533, - 3238325178821009741, - 2344850491864189019 - ], - [ - 9070724167014080545, - 4270936005334206500, - 14011092173278602876, - 17233390044312666340 - ], - [ - 15882294806312417165, - 4574813182503183418, - 15374759504522847393, - 12609068726586761599 - ], - [ - 5081359810005150600, - 3073725930902770385, - 12151383627606620216, - 1678712612408922293 - ], - [ - 13389075440637154488, - 1394733244174774927, - 15897027408886080730, - 8756205416909346149 - ], - [ - 9635595243774498130, - 12944626865667316474, - 11443383015868895087, - 11271399114434241688 - ], - [ - 15730316965377191644, - 9302195093067483199, - 13013113029527355010, - 16107136888029757437 - ], - [ - 4376996761649023946, - 5151155327098069058, - 5052643273518683586, - 4214154406154441301 - ], - [ - 14323780220991293990, - 8193587898306996901, - 5671887774622993207, - 9546628649033002185 - ], - [ - 16523271232278987128, - 994857983084927437, - 14501829109938165419, - 9015660151307809950 - ], - [ - 1530238726285436995, - 6261885523422263637, - 11940153058268689285, - 15737357444014615384 - ], - [ - 2670341602838046451, - 10669331667080282584, - 16656965855764533819, - 13339778044433609883 - ], - [ - 17128805815986618686, - 18194734266790270296, - 5735422502154213482, - 10164141197176685232 - ], - [ - 2629176720116777217, - 6966722226648521547, - 2937669813272776408, - 2812827195714811672 - ], - [ - 6178870790111010071, - 10834984121929556338, - 2836091052290008872, - 1311164878771236983 - ], - [ - 7411275786539821863, - 3702190765468277039, - 18130480549896087952, - 5277641488054089382 - ] - ] - } -} \ No newline at end of file diff --git a/prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json b/prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json deleted file mode 100644 index 821a2d6e3881..000000000000 --- a/prover/vk_setup_data_generator_server_fri/data/witness_artifacts.json +++ /dev/null @@ -1 +0,0 @@ -{"entry_point_address":"0xc54e30abb6a3eed1b9dc0494d90c9c22d76fba7e","entry_point_code":[[0,4,0,0,0,0,0,2,0,10,0,0,0,0,0,2,0,0,0,0,3,1,0,25,0,0,0,96,4,48,2,112],[0,0,3,119,3,64,1,151,0,3,0,0,0,49,3,85,0,2,0,0,0,1,3,85,0,0,3,119,0,64,1,157],[0,0,0,1,2,32,1,144,0,0,0,93,0,0,193,61,0,0,0,128,2,0,0,57,0,0,0,64,0,32,4,63],[0,0,0,4,2,48,0,140,0,0,0,144,0,0,65,61,0,0,0,0,1,1,4,59,0,0,0,224,1,16,2,112],[0,0,3,201,2,16,0,156,0,0,2,111,0,0,161,61,0,0,3,202,2,16,0,156,0,0,2,136,0,0,33,61],[0,0,3,209,2,16,0,156,0,0,2,186,0,0,161,61,0,0,3,210,2,16,0,156,0,0,2,245,0,0,97,61],[0,0,3,211,2,16,0,156,0,0,2,227,0,0,97,61,0,0,3,212,1,16,0,156,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,3,228,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,229,1,16,1,199,0,0,0,2,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,4,64,2,114,0,0,0,58,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,70,0,75,0,0,0,51,0,0,65,61,0,0,0,0,6,5,0,75,0,0,0,72,0,0,97,61],[0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207],[0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,64,8,0,4,61,0,0,0,1,2,32,1,144],[0,0,3,184,0,0,97,61,0,0,0,0,1,0,4,51,0,0,3,230,1,16,1,103,0,0,0,64,2,128,0,57],[0,0,0,0,0,18,4,53,0,0,0,32,1,128,0,57,0,0,3,230,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,64,1,0,0,57,0,0,0,0,0,24,4,53,0,0,0,0,1,8,0,25,0,10,0,0,0,8,0,29],[13,214,7,244,0,0,4,15,0,0,0,10,1,0,0,41,13,214,10,230,0,0,4,15,0,0,0,0,1,0,0,25],[0,0,13,216,0,1,4,48,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,3,120,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,16,0,10,0,0,0,1,0,29],[0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,121,1,16,1,199,0,0,128,2,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,3,122,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,10,1,0,0,41,0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,121,1,16,1,199],[0,0,128,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,3,123,1,16,0,156,0,0,5,32,0,0,193,61,0,0,3,124,1,0,0,65],[0,0,0,160,0,16,4,63,0,0,0,4,1,0,0,57,0,0,0,128,0,16,4,63,0,0,0,192,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,0,0,1,0,4,20,0,0,0,10,2,0,0,41,0,0,0,4,3,32,0,140],[0,0,3,13,0,0,193,61,0,0,0,1,2,0,0,57,0,0,0,1,3,0,0,49,0,0,3,24,0,0,1,61],[0,0,0,0,1,3,0,75,0,0,5,32,0,0,193,61,0,0,3,129,1,0,0,65,0,0,0,0,2,1,4,26],[0,0,0,0,2,2,0,75,0,0,5,32,0,0,193,61,0,0,0,1,2,0,0,57,0,5,0,0,0,2,0,29],[0,0,0,0,0,33,4,27,0,0,0,0,1,0,4,18,0,0,3,130,1,16,1,151,0,0,0,0,2,0,4,16],[0,0,0,0,1,33,0,75,0,0,2,160,0,0,193,61,0,2,0,0,0,2,0,29,0,0,3,134,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,3,37,0,0,193,61,0,0,3,136,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,10,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,137,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,9,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,138,3,48,1,151],[0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,3,139,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,8,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,140,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,7,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,141,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,142,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,27],[0,0,3,143,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,3,130,1,16,1,151,0,0,0,4,2,0,0,57,0,0,0,0,3,2,4,26],[0,0,3,138,3,48,1,151,0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,0,2,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,3,144,2,32,1,151,0,0,0,2,3,0,3,103,0,0,0,0,3,3,4,59],[0,0,0,224,3,48,2,112,0,0,0,0,2,50,1,159,0,0,0,0,0,33,4,27,0,0,3,134,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,5,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,0,11,1,0,0,57,0,0,0,0,2,0,4,22,0,0,0,0,0,33,4,27],[0,0,0,0,1,0,4,20,0,1,0,0,0,1,0,29,0,0,0,64,1,0,4,61,0,0,0,0,5,1,0,25],[0,0,3,145,1,16,0,156,0,0,3,58,0,0,33,61,0,0,0,160,1,80,0,57,0,0,0,64,0,16,4,63],[0,0,0,128,1,80,0,57,0,0,3,146,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,96,1,80,0,57],[0,0,3,147,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,64,1,80,0,57,0,0,3,148,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,122,1,0,0,57,0,0,0,0,10,21,4,54,0,0,3,149,1,0,0,65],[0,0,0,0,0,26,4,53,0,4,128,16,0,0,0,61,0,8,0,0,0,0,0,29,0,10,0,0,0,5,0,29],[0,0,3,119,1,160,0,156,0,0,3,119,4,0,0,65,0,0,0,0,10,4,128,25,0,0,0,64,1,160,2,16],[0,0,0,0,2,5,4,51,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,0,4,2,0,0,41],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,32,0,0,97,61,0,0,0,64,2,0,4,61],[0,0,0,0,1,1,4,59,0,9,0,0,0,1,0,29,0,0,0,10,6,0,0,41,0,0,0,0,1,6,4,51],[0,0,0,0,3,1,0,75,0,0,1,110,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,35,0,25],[0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53],[0,0,0,0,4,19,0,75,0,0,1,103,0,0,65,61,0,0,0,0,3,33,0,25,0,0,0,0,0,3,4,53],[0,0,3,119,3,32,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16],[0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,0,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,5,3,0,25],[0,0,0,32,5,0,128,57,0,0,0,5,4,80,2,114,0,0,1,143,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,1,136,0,0,65,61,0,0,0,31,5,80,1,144],[0,0,1,157,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,64,11,0,4,61],[0,0,0,1,2,32,1,144,0,0,3,251,0,0,97,61,0,0,0,0,2,0,4,51,0,0,0,32,12,176,0,57],[0,0,0,10,6,0,0,41,0,0,0,0,1,6,4,51,0,0,0,0,3,1,0,75,0,0,1,176,0,0,97,61],[0,0,0,0,3,0,0,25,0,0,0,0,4,195,0,25,0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25],[0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,0,4,19,0,75,0,0,1,169,0,0,65,61],[0,0,0,9,2,32,1,79,0,0,0,0,3,193,0,25,0,0,0,0,0,35,4,53,0,0,0,32,3,16,0,57],[0,0,0,0,0,59,4,53,0,0,0,95,3,16,0,57,0,0,0,32,1,0,0,138,0,0,0,0,3,19,1,111],[0,0,0,0,13,179,0,25,0,0,0,0,3,61,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,0,3,127,4,208,0,156,0,0,3,58,0,0,33,61,0,0,0,1,3,48,1,144,0,0,3,58,0,0,193,61],[0,0,0,64,0,208,4,63,0,0,0,12,10,0,0,57,0,0,0,0,3,10,4,26,0,0,3,127,4,48,0,156],[0,0,3,58,0,0,33,61,0,0,0,1,4,48,0,57,0,0,0,0,0,74,4,27,0,0,0,0,0,160,4,53],[0,0,3,151,3,48,0,65,0,0,0,0,0,35,4,27,0,0,0,0,3,10,4,26,0,0,0,0,4,3,0,75],[0,0,3,52,0,0,97,61,0,0,0,1,6,48,0,140,0,0,0,5,3,0,0,41,0,0,1,233,0,0,97,61],[0,0,0,0,3,10,4,26,0,0,0,0,4,99,0,75,0,0,5,3,0,0,161,61,0,0,0,1,4,96,0,138],[0,0,0,1,5,64,2,112,0,0,0,0,7,83,0,75,0,0,5,3,0,0,161,61,0,0,3,151,7,96,0,65],[0,0,0,0,9,7,4,26,0,0,0,0,0,160,4,53,0,0,3,151,6,80,0,65,0,0,0,0,8,6,4,26],[0,0,0,0,9,137,0,75,0,0,1,233,0,0,161,61,0,0,0,0,0,135,4,27,0,0,0,0,3,10,4,26],[0,0,0,0,3,83,0,75,0,0,5,3,0,0,161,61,0,0,0,0,0,38,4,27,0,0,0,2,3,64,0,140],[0,0,0,0,6,5,0,25,0,0,1,208,0,0,129,61,0,0,0,0,3,10,4,26,0,0,0,0,2,3,0,75],[0,0,3,52,0,0,97,61,0,0,0,1,2,48,0,138,0,0,0,0,2,35,1,112,0,0,1,245,0,0,193,61],[0,0,0,13,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,127,4,48,1,151,0,0,3,127,5,64,0,156],[0,0,3,52,0,0,97,61,0,0,3,152,3,48,1,151,0,0,0,1,4,64,0,57,0,0,0,0,3,52,1,159],[0,0,0,0,0,50,4,27,0,7,0,0,0,12,0,29,0,10,0,0,0,10,0,29,0,0,3,153,2,0,0,65],[0,0,0,0,0,45,4,53,0,0,0,4,2,208,0,57,0,0,0,32,3,0,0,57,0,3,0,0,0,3,0,29],[0,0,0,0,0,50,4,53,0,0,0,0,2,11,4,51,0,0,0,36,3,208,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,3,208,0,57,0,0,0,0,4,2,0,75,0,0,2,11,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,180,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,2,4,0,0,65,61,0,9,0,0,0,11,0,29],[0,0,0,0,3,50,0,25,0,0,0,0,0,3,4,53,0,0,0,31,2,32,0,57,0,0,0,0,1,18,1,111],[0,0,3,119,2,208,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,0,25,0,0,0,0,2,13,64,25],[0,0,0,64,2,32,2,16,0,0,0,68,1,16,0,57,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57],[0,6,0,0,0,13,0,29,13,214,13,204,0,0,4,15,0,0,0,6,11,0,0,41,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,5,5,64,2,114,0,0,2,52,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,123,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,2,44,0,0,65,61],[0,0,0,31,6,64,1,144,0,0,0,10,9,0,0,41,0,0,0,7,10,0,0,41,0,0,2,69,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,7,81,3,79,0,0,0,0,5,91,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,8,5,4,51,0,0,0,0,8,104,1,207,0,0,0,0,8,104,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,7,103,2,47,0,0,0,0,6,103,1,207,0,0,0,0,6,134,1,159],[0,0,0,0,0,101,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,0,9,5,0,0,41,0,0,4,27,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143],[0,0,0,0,1,178,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,3,127,4,16,0,156,0,0,3,58,0,0,33,61,0,0,0,1,2,32,1,144,0,0,3,58,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,32,2,48,0,140,0,0,5,32,0,0,65,61,0,0,0,8,3,0,0,41],[0,0,0,2,2,48,0,140,0,8,0,1,0,48,0,61,0,0,1,75,0,0,161,61,0,0,0,0,2,9,4,26],[0,0,0,0,3,2,0,75,0,0,4,60,0,0,193,61,0,0,0,68,2,16,0,57,0,0,3,198,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,1,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,3,131,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,3,3,0,0,41],[0,0,0,0,0,50,4,53,0,0,3,119,2,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,3,159,1,16,1,199,0,0,13,216,0,1,4,48,0,0,3,215,2,16,0,156],[0,0,2,149,0,0,161,61,0,0,3,216,2,16,0,156,0,0,2,179,0,0,161,61,0,0,3,217,2,16,0,156],[0,0,2,222,0,0,97,61,0,0,3,218,2,16,0,156,0,0,2,217,0,0,97,61,0,0,3,219,1,16,0,156],[0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,12,1,0,0,57,0,0,0,0,5,1,4,26,0,0,0,0,2,5,0,75,0,0,3,107,0,0,193,61],[0,0,3,131,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,1,1,0,0,57,0,0,0,164,0,16,4,63,0,0,3,198,1,0,0,65,0,0,2,167,0,0,1,61],[0,0,3,203,2,16,0,156,0,0,2,196,0,0,161,61,0,0,3,204,2,16,0,156,0,0,2,251,0,0,97,61],[0,0,3,205,2,16,0,156,0,0,2,232,0,0,97,61,0,0,3,206,1,16,0,156,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,4,1,0,0,57],[0,0,2,242,0,0,1,61,0,0,3,222,2,16,0,156,0,0,2,170,0,0,33,61,0,0,3,225,2,16,0,156],[0,0,2,205,0,0,97,61,0,0,3,226,1,16,0,156,0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,3,1,0,0,57,0,0,3,9,0,0,1,61],[0,0,3,131,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,16,1,0,0,57,0,0,0,164,0,16,4,63,0,0,3,132,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,3,133,1,0,0,65,0,0,13,216,0,1,4,48,0,0,3,223,2,16,0,156,0,0,2,210,0,0,97,61],[0,0,3,224,1,16,0,156,0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,6,1,0,0,57,0,0,3,9,0,0,1,61,0,0,3,220,2,16,0,156],[0,0,2,238,0,0,97,61,0,0,3,221,1,16,0,156,0,0,5,32,0,0,193,61,13,214,7,255,0,0,4,15],[0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46,0,0,3,213,2,16,0,156,0,0,3,0,0,0,97,61],[0,0,3,214,1,16,0,156,0,0,5,32,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,13,214,11,176,0,0,4,15,0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46],[0,0,3,207,2,16,0,156,0,0,3,5,0,0,97,61,0,0,3,208,1,16,0,156,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,11,1,0,0,57],[0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,0,1,0,4,26,0,0,2,243,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,2,1,0,0,57,0,0,0,0,1,1,4,26,0,0,0,224,1,16,2,16],[0,0,3,10,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,10,1,0,0,57,0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,7,1,0,0,57,0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,3,124,1,0,0,65,0,0,3,10,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,13,214,11,113,0,0,4,15],[0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,5,32,0,0,193,61,0,0,0,9,1,0,0,57,0,0,0,0,1,1,4,26,0,0,3,130,1,16,1,151],[0,0,3,10,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[13,214,8,206,0,0,4,15,0,0,0,0,1,0,0,25,0,0,13,215,0,1,4,46,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,5,1,0,0,57,0,0,3,9,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61,0,0,0,8,1,0,0,57],[0,0,3,9,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,1,1,0,0,57,0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,3,227,1,0,0,65],[0,0,13,215,0,1,4,46,0,0,3,119,4,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25],[0,0,0,192,1,16,2,16,0,0,3,125,1,16,1,199,13,214,13,204,0,0,4,15,0,0,0,1,2,32,1,143],[0,3,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,1,3,119,0,16,1,157,0,0,3,119,3,16,1,151],[0,0,0,96,1,0,0,57,0,0,0,0,4,3,0,75,0,0,3,56,0,0,193,61,0,0,0,0,2,2,0,75],[0,0,5,32,0,0,97,61,0,0,0,0,1,1,4,51,0,0,0,0,1,1,0,75,0,0,5,32,0,0,193,61],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,3,128,1,0,0,65],[0,0,13,215,0,1,4,46,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,3,218,0,0,193,61],[0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,5,6,0,0,1,61],[0,0,3,126,1,48,0,156,0,0,3,62,0,0,65,61,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,5,6,0,0,1,61,0,0,0,31,1,48,0,57,0,0,0,32,4,0,0,138],[0,0,0,0,1,65,1,111,0,0,0,63,1,16,0,57,0,0,0,0,4,65,1,111,0,0,0,64,1,0,4,61],[0,0,0,0,4,65,0,25,0,0,0,0,5,20,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,3,127,6,64,0,156,0,0,3,58,0,0,33,61,0,0,0,1,5,80,1,144,0,0,3,58,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,31,4,48,1,143,0,0,0,0,5,49,4,54,0,0,0,3,6,0,3,103],[0,0,0,5,3,48,2,114,0,0,3,91,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,133,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,55,0,75,0,0,3,83,0,0,65,61,0,0,0,0,7,4,0,75],[0,0,3,27,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,6,54,3,79,0,0,0,0,3,53,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,5,3,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,6,6,4,59,0,0,1,0,4,64,0,137,0,0,0,0,6,70,2,47,0,0,0,0,4,70,1,207],[0,0,0,0,4,84,1,159,0,0,0,0,0,67,4,53,0,0,3,27,0,0,1,61,0,0,3,151,2,0,0,65],[0,0,0,1,3,0,0,57,0,0,3,157,4,0,0,65,0,0,3,119,0,0,1,61,0,0,0,1,6,0,0,138],[0,0,0,0,6,101,0,75,0,0,3,52,0,0,97,61,0,0,0,1,6,80,0,57,0,0,0,0,6,86,1,112],[0,0,3,174,0,0,97,61,0,0,0,0,6,5,0,75,0,0,3,249,0,0,97,61,0,0,3,154,6,80,0,65],[0,0,0,0,7,6,4,26,0,0,0,0,0,114,4,27,0,0,0,0,0,6,4,27,0,0,0,1,5,80,0,138],[0,0,0,0,0,81,4,27,0,0,0,2,6,80,0,140,0,0,3,114,0,0,65,61,0,0,0,0,8,3,0,25],[0,0,0,0,9,0,0,25,0,0,0,0,7,0,0,25,0,0,0,2,10,144,0,57,0,0,0,0,6,90,0,75],[0,0,0,0,6,8,0,25,0,0,3,141,0,0,129,61,0,0,3,155,6,144,0,65,0,0,0,0,6,6,4,26],[0,0,3,156,9,144,0,65,0,0,0,0,9,9,4,26,0,0,0,0,6,105,0,75,0,0,0,0,6,8,0,25],[0,0,0,0,6,10,64,25,0,0,0,0,8,101,0,75,0,0,5,3,0,0,161,61,0,0,3,151,8,96,0,65],[0,0,0,0,9,117,0,75,0,0,5,3,0,0,161,61,0,0,0,0,9,8,4,26,0,0,3,151,10,112,0,65],[0,0,0,0,7,10,4,26,0,0,0,0,11,121,0,75,0,0,3,111,0,0,161,61,0,0,0,0,0,154,4,27],[0,0,0,0,5,1,4,26,0,0,0,0,5,101,0,75,0,0,5,3,0,0,161,61,0,0,0,0,0,120,4,27],[0,0,0,0,5,6,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,64,25,0,0,3,157,7,96,1,151],[0,0,0,0,8,7,0,75,0,0,0,0,8,0,0,25,0,0,0,0,8,4,32,25,0,0,3,157,7,112,0,156],[0,0,0,0,8,5,192,25,0,0,0,0,5,8,0,75,0,0,3,52,0,0,193,61,0,0,0,0,5,1,4,26],[0,0,0,1,9,96,2,16,0,0,0,1,8,144,1,191,0,0,0,0,7,88,0,75,0,0,0,0,7,6,0,25],[0,0,3,130,0,0,65,61,0,0,3,111,0,0,1,61,0,0,0,13,6,0,0,57,0,0,0,0,7,6,4,26],[0,0,3,127,8,112,1,151,0,0,0,1,8,128,0,138,0,0,3,127,9,128,0,156,0,0,3,52,0,0,33,61],[0,0,3,152,7,112,1,151,0,0,0,0,7,120,1,159,0,0,0,0,0,118,4,27,0,0,3,117,0,0,1,61],[0,0,0,31,2,48,1,143,0,0,0,5,4,48,2,114,0,0,3,196,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,3,188,0,0,65,61],[0,0,0,0,5,2,0,75,0,0,3,211,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79],[0,0,0,0,4,72,0,25,0,0,0,3,2,32,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,37,1,207],[0,0,0,0,5,37,2,47,0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47],[0,0,0,0,1,33,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65],[0,0,3,119,2,128,0,156,0,0,0,0,8,1,128,25,0,0,0,64,1,128,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,13,216,0,1,4,48,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,10,0,0,0,1,0,29],[0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156],[0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61,0,0,0,10,2,0,0,41],[0,0,3,232,2,32,0,57,0,0,0,0,1,1,4,59,0,0,0,0,1,33,0,75,0,0,3,52,0,0,33,61],[0,0,0,174,0,0,1,61,0,0,0,0,0,16,4,53,0,0,2,128,0,0,1,61,0,0,0,31,2,48,1,143],[0,0,0,5,4,48,2,114,0,0,4,7,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,107,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,3,255,0,0,65,61,0,0,0,0,5,2,0,75],[0,0,4,22,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79,0,0,0,0,4,75,0,25],[0,0,0,3,2,32,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,37,1,207,0,0,0,0,5,37,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65,0,0,3,119,2,176,0,156],[0,0,0,0,11,1,128,25,0,0,0,64,1,176,2,16,0,0,3,215,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,4,40,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,4,32,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,4,55,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,119,1,0,0,65],[0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,3,215,0,0,1,61],[0,0,3,154,3,32,0,65,0,0,0,0,4,3,4,26,0,0,3,151,5,0,0,65,0,0,0,0,0,69,4,27],[0,0,0,10,10,0,0,41,0,0,0,0,0,160,4,53,0,0,0,0,0,3,4,27,0,0,0,1,3,32,0,138],[0,0,0,0,0,58,4,27,0,0,0,2,2,48,0,140,0,0,4,122,0,0,65,61,0,0,0,1,6,0,0,57],[0,0,3,157,2,0,0,65,0,0,0,0,7,0,0,25,0,0,0,0,5,0,0,25,0,0,0,2,8,112,0,57],[0,0,0,0,4,56,0,75,0,0,0,0,4,6,0,25,0,0,4,86,0,0,129,61,0,0,3,155,4,112,0,65],[0,0,0,0,4,4,4,26,0,0,3,156,7,112,0,65,0,0,0,0,7,7,4,26,0,0,0,0,4,71,0,75],[0,0,0,0,4,6,0,25,0,0,0,0,4,8,64,25,0,0,0,0,6,67,0,75,0,0,5,3,0,0,161,61],[0,0,3,151,6,64,0,65,0,0,0,0,7,83,0,75,0,0,5,3,0,0,161,61,0,0,0,0,7,6,4,26],[0,0,0,0,0,160,4,53,0,0,3,151,8,80,0,65,0,0,0,0,5,8,4,26,0,0,0,0,9,87,0,75],[0,0,4,119,0,0,161,61,0,0,0,0,0,120,4,27,0,0,0,0,3,10,4,26,0,0,0,0,3,67,0,75],[0,0,5,3,0,0,161,61,0,0,0,0,0,86,4,27,0,0,0,0,3,4,0,75,0,0,0,0,3,0,0,25],[0,0,0,0,3,2,64,25,0,0,3,157,5,64,1,151,0,0,0,0,6,5,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,2,32,25,0,0,3,157,5,80,0,156,0,0,0,0,6,3,192,25,0,0,0,0,3,6,0,75],[0,0,3,52,0,0,193,61,0,0,0,0,3,10,4,26,0,0,0,1,7,64,2,16,0,0,0,1,6,112,1,191],[0,0,0,0,5,54,0,75,0,0,0,0,5,4,0,25,0,0,4,75,0,0,65,61,0,0,0,1,2,0,0,138],[0,0,0,0,2,35,0,75,0,0,3,52,0,0,97,61,0,0,0,1,2,48,0,57,0,0,0,0,2,50,1,112],[0,0,4,134,0,0,193,61,0,0,0,13,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,127,4,48,1,151],[0,0,0,1,4,64,0,138,0,0,3,127,5,64,0,156,0,0,3,52,0,0,33,61,0,0,3,152,3,48,1,151],[0,0,0,0,3,52,1,159,0,0,0,0,0,50,4,27,0,0,0,0,3,0,4,20,0,8,0,0,0,3,0,29],[0,0,0,1,2,48,0,107,0,0,5,9,0,0,161,61,0,0,0,9,6,0,0,41,0,0,0,0,2,6,4,51],[0,0,0,0,3,2,0,75,0,0,4,150,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,19,0,25],[0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53],[0,0,0,0,4,35,0,75,0,0,4,143,0,0,65,61,0,0,0,0,3,18,0,25,0,0,0,0,0,3,4,53],[0,0,3,119,4,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,128,16,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,5,32,0,0,97,61,0,0,0,8,3,0,0,41,0,0,0,1,2,48,0,105],[0,0,0,0,5,1,4,59,0,0,0,64,1,0,4,61,0,0,0,0,0,33,4,53,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,3,119,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,3,160,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57,0,0,3,161,4,0,0,65],[13,214,13,204,0,0,4,15,0,0,0,10,5,0,0,41,0,0,0,1,1,32,1,144,0,0,5,32,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,3,162,1,32,0,156,0,0,3,58,0,0,33,61,0,0,0,192,1,32,0,57],[0,0,0,64,0,16,4,63,0,0,0,160,1,32,0,57,0,0,3,163,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,128,3,32,0,57,0,0,3,164,1,0,0,65,0,0,0,0,0,19,4,53,0,0,0,96,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,32,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,135,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,64,2,0,4,61],[0,0,3,162,3,32,0,156,0,0,3,58,0,0,33,61,0,0,0,192,3,32,0,57,0,0,0,64,0,48,4,63],[0,0,0,160,3,32,0,57,0,0,3,165,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,128,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,96,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,64,3,32,0,57],[0,0,0,0,0,19,4,53,0,0,0,32,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,136,1,0,0,57],[0,0,0,0,0,18,4,53,0,0,0,64,1,0,4,61,0,0,3,162,2,16,0,156,0,0,3,58,0,0,33,61],[0,0,0,192,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,160,2,16,0,57,0,0,3,166,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,128,2,16,0,57,0,0,3,164,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,96,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,50,4,53],[0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,137,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,0,0,1,5,4,26,0,9,0,0,0,1,0,29,0,0,0,0,1,1,0,75,0,0,5,15,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,3,197,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,24,3,0,0,57,0,0,2,99,0,0,1,61,0,0,3,199,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65],[0,0,13,216,0,1,4,48,0,0,0,68,2,16,0,57,0,0,3,158,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,18,3,0,0,57,0,0,2,99,0,0,1,61,0,0,3,120,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,2,1,0,0,41,0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,3,121,1,16,1,199,0,0,128,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,5,147,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,5,34,0,0,193,61],[0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48,0,0,0,64,2,0,4,61,0,0,3,167,1,0,0,65],[0,8,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,0,1,0,4,20,0,0,0,2,2,0,0,41],[0,0,0,4,2,32,0,140,0,0,5,60,0,0,97,61,0,0,3,119,2,0,0,65,0,0,3,119,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,8,4,0,0,41,0,0,3,119,3,64,0,156,0,0,0,0,2,4,64,25],[0,0,0,64,2,32,2,16,0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159,0,0,3,168,1,16,1,199],[0,0,0,2,2,0,0,41,13,214,13,204,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,3,119,0,48,1,157,0,3,0,0,0,1,3,85,0,0,0,1,1,32,1,144,0,0,5,82,0,0,97,61],[0,0,0,8,1,0,0,41,0,0,3,127,1,16,0,156,0,0,3,58,0,0,33,61,0,0,0,8,3,0,0,41],[0,0,0,64,0,48,4,63,0,0,0,68,1,48,0,57,0,0,3,196,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,48,0,57,0,0,0,23,2,0,0,57,0,0,0,0,0,33,4,53,0,0,3,131,1,0,0,65],[0,0,0,0,0,19,4,53,0,0,0,4,1,48,0,57,0,0,0,3,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,3,119,1,0,0,65,0,0,3,119,2,48,0,156,0,0,0,0,3,1,128,25,0,0,0,64,1,48,2,16],[0,0,3,159,1,16,1,199,0,0,13,216,0,1,4,48,0,0,0,10,1,0,0,41,0,0,0,0,1,1,4,26],[0,0,0,9,1,16,0,108,0,0,5,148,0,0,193,61,0,0,3,120,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,2,1,0,0,41,0,0,0,4,0,16,4,67,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,3,121,1,16,1,199],[0,0,128,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,5,147,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,5,32,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,3,170,1,0,0,65,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,64,0,156,0,10,0,0,0,4,0,29],[0,0,0,0,1,4,64,25,0,9,0,64,0,16,2,24,0,0,0,192,1,32,2,16,0,0,0,9,1,16,1,175],[0,0,3,168,1,16,1,199,0,0,0,2,2,0,0,41,13,214,13,204,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,1,3,119,0,48,1,157,0,3,0,0,0,1,3,85,0,0,0,1,1,32,1,144],[0,0,5,155,0,0,97,61,0,0,0,10,1,0,0,41,0,0,3,127,1,16,0,156,0,0,3,58,0,0,33,61],[0,0,0,10,3,0,0,41,0,0,0,64,0,48,4,63,0,0,0,100,1,48,0,57,0,0,3,193,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,68,1,48,0,57,0,0,3,194,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,48,0,57,0,0,0,38,2,0,0,57,0,0,0,0,0,33,4,53,0,0,3,131,1,0,0,65],[0,0,0,0,0,19,4,53,0,0,0,4,1,48,0,57,0,0,0,3,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,9,1,0,0,41,0,0,3,195,1,16,1,199,0,0,13,216,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,3,169,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,27,3,0,0,57,0,0,2,99,0,0,1,61,0,0,0,64,1,0,4,61],[0,0,3,171,2,16,0,156,0,0,3,58,0,0,33,61,0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63],[0,0,3,172,2,0,0,65,0,0,0,0,2,33,4,54,0,0,0,64,4,0,4,61,0,0,3,173,3,64,0,156],[0,0,3,58,0,0,33,61,0,0,0,128,3,64,0,57,0,0,0,64,0,48,4,63,0,0,0,96,3,64,0,57],[0,0,3,174,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,64,3,64,0,57,0,0,3,175,5,0,0,65],[0,0,0,0,0,83,4,53,0,0,0,32,3,64,0,57,0,0,3,176,5,0,0,65,0,0,0,0,0,83,4,53],[0,0,0,65,3,0,0,57,0,9,0,0,0,3,0,29,0,0,0,0,0,52,4,53,0,0,0,64,3,16,0,57],[0,0,3,177,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,0,0,66,4,53,0,0,0,64,4,0,4,61],[0,10,0,0,0,4,0,29,0,0,3,171,4,64,0,156,0,0,3,58,0,0,33,61,0,0,0,10,5,0,0,41],[0,0,0,96,4,80,0,57,0,0,0,64,0,64,4,63,0,0,3,178,4,0,0,65,0,0,0,0,4,69,4,54],[0,8,0,0,0,4,0,29,0,0,0,64,4,0,4,61,0,0,3,173,5,64,0,156,0,0,3,58,0,0,33,61],[0,0,0,128,5,64,0,57,0,0,0,64,0,80,4,63,0,0,0,96,5,64,0,57,0,0,3,174,6,0,0,65],[0,0,0,0,0,101,4,53,0,0,0,64,5,64,0,57,0,0,3,179,6,0,0,65,0,0,0,0,0,101,4,53],[0,0,0,32,5,64,0,57,0,0,3,180,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,9,5,0,0,41],[0,0,0,0,0,84,4,53,0,0,0,10,5,0,0,41,0,0,0,64,6,80,0,57,0,0,3,181,5,0,0,65],[0,7,0,0,0,6,0,29,0,0,0,0,0,86,4,53,0,0,0,8,5,0,0,41,0,0,0,0,0,69,4,53],[0,0,0,0,2,2,4,51,0,0,0,0,84,2,4,52,0,0,0,65,4,64,0,140,0,0,5,32,0,0,193,61],[0,0,0,65,4,32,0,57,0,0,0,0,4,4,4,51,0,0,0,255,4,64,1,143,0,0,0,27,6,64,0,138],[0,0,0,1,6,96,0,140,0,0,5,32,0,0,33,61,0,0,0,0,3,3,4,51,0,6,0,0,0,3,0,29],[0,0,0,0,1,1,4,51,0,0,0,0,3,5,4,51,0,0,0,64,2,32,0,57,0,0,0,0,2,2,4,51],[0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,38,4,53,0,0,0,64,2,80,0,57],[0,0,0,0,0,50,4,53,0,0,0,32,2,80,0,57,0,0,0,0,0,66,4,53,0,0,0,0,0,21,4,53],[0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,4,64,2,114,0,0,6,14,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,70,0,75,0,0,6,7,0,0,65,61,0,0,0,0,6,5,0,75,0,0,6,28,0,0,97,61],[0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207],[0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,7,64,0,0,97,61],[0,0,0,0,1,0,4,51,0,0,0,6,1,16,1,79,0,0,3,130,1,16,1,152,0,0,5,32,0,0,193,61],[0,0,0,8,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,0,50,1,4,52,0,0,0,65,2,32,0,140],[0,0,5,32,0,0,193,61,0,0,0,65,2,16,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143],[0,0,0,27,4,32,0,138,0,0,0,1,4,64,0,140,0,0,5,32,0,0,33,61,0,0,0,7,4,0,0,41],[0,0,0,0,4,4,4,51,0,8,0,0,0,4,0,29,0,0,0,10,4,0,0,41,0,0,0,0,4,4,4,51],[0,0,0,0,3,3,4,51,0,0,0,64,1,16,0,57,0,0,0,0,1,1,4,51,0,0,0,64,5,0,4,61],[0,0,0,96,6,80,0,57,0,0,0,0,0,22,4,53,0,0,0,64,1,80,0,57,0,0,0,0,0,49,4,53],[0,0,0,32,1,80,0,57,0,0,0,0,0,33,4,53,0,0,0,0,0,69,4,53,0,0,0,0,0,0,4,53],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,6,93,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,6,86,0,0,65,61,0,0,0,0,6,5,0,75,0,0,6,107,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,7,93,0,0,97,61,0,0,0,0,1,0,4,51],[0,0,0,8,1,16,1,79,0,0,3,130,1,16,1,152,0,0,5,32,0,0,193,61,0,0,0,64,1,0,4,61],[0,0,3,171,2,16,0,156,0,0,3,58,0,0,33,61,0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63],[0,0,0,0,5,1,4,54,0,0,0,64,2,0,4,61,0,0,3,173,3,32,0,156,0,0,3,58,0,0,33,61],[0,0,0,128,3,32,0,57,0,0,0,64,0,48,4,63,0,0,0,96,3,32,0,57,0,0,3,174,4,0,0,65],[0,0,0,0,0,67,4,53,0,0,0,64,3,32,0,57,0,0,3,183,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,32,4,32,0,57,0,0,3,184,6,0,0,65,0,0,0,0,0,100,4,53,0,0,0,9,6,0,0,41],[0,0,0,0,0,98,4,53,0,0,0,64,6,16,0,57,0,0,3,185,7,0,0,65,0,0,0,0,0,118,4,53],[0,0,0,0,0,37,4,53,0,0,0,0,5,2,4,51,0,0,0,65,5,80,0,140,0,0,5,32,0,0,193,61],[0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138],[0,0,0,1,5,80,0,140,0,0,5,32,0,0,33,61,0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51],[0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53],[0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53,0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53],[0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199],[0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,6,191,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,6,184,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,6,205,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,7,122,0,0,97,61,0,0,0,0,1,0,4,51,0,0,3,130,1,16,1,151,0,0,3,185,1,16,0,156],[0,0,5,32,0,0,193,61,0,0,0,64,1,0,4,61,0,0,3,171,2,16,0,156,0,0,3,58,0,0,33,61],[0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63,0,0,3,186,2,0,0,65,0,0,0,0,5,33,4,54],[0,0,0,64,2,0,4,61,0,0,3,173,3,32,0,156,0,0,3,58,0,0,33,61,0,0,0,128,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,96,3,32,0,57,0,0,3,187,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,64,3,32,0,57,0,0,3,188,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,32,4,32,0,57],[0,0,3,189,6,0,0,65,0,0,0,0,0,100,4,53,0,0,0,9,6,0,0,41,0,0,0,0,0,98,4,53],[0,0,0,0,0,37,4,53,0,0,0,64,5,16,0,57,0,0,0,0,0,5,4,53,0,0,0,0,5,2,4,51],[0,0,0,65,5,80,0,140,0,0,5,32,0,0,193,61,0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51],[0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138,0,0,0,1,5,80,0,140,0,0,5,32,0,0,33,61],[0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51,0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61],[0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53,0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53],[0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53,0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,7,33,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,7,26,0,0,65,61,0,0,0,0,6,5,0,75,0,0,7,47,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,7,151,0,0,97,61,0,0,0,0,1,0,4,51],[0,0,3,130,1,16,1,152,0,0,5,32,0,0,193,61,0,0,0,0,3,0,4,22,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,0,2,3,0,75,0,0,7,180,0,0,193,61,0,0,3,190,2,0,0,65,0,0,7,184,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,7,77,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,7,69,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,92,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,4,55,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,7,106,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,7,98,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,121,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,4,55,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,7,135,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,127,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,7,150,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,4,55,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,7,164,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,156,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,7,179,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,4,55,0,0,1,61],[0,0,3,150,1,16,1,199,0,0,128,9,2,0,0,57,0,0,3,190,4,0,0,65,0,0,0,0,5,0,0,25],[13,214,13,204,0,0,4,15,0,3,0,0,0,1,3,85,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,3,119,0,48,1,157,0,0,3,119,5,48,1,152,0,0,7,231,0,0,97,61,0,0,0,63,3,80,0,57],[0,0,3,191,3,48,1,151,0,0,0,64,4,0,4,61,0,0,0,0,3,52,0,25,0,0,0,0,6,67,0,75],[0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57,0,0,3,127,7,48,0,156,0,0,3,58,0,0,33,61],[0,0,0,1,6,96,1,144,0,0,3,58,0,0,193,61,0,0,0,64,0,48,4,63,0,0,0,31,3,80,1,143],[0,0,0,0,4,84,4,54,0,0,0,5,5,80,2,114,0,0,7,216,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,208,0,0,65,61],[0,0,0,0,6,3,0,75,0,0,7,231,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,4,84,0,25,0,0,0,3,3,48,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,0,1,1,32,1,144],[0,0,7,237,0,0,97,61,0,0,3,129,1,0,0,65,0,0,0,0,0,1,4,27,0,0,0,0,1,0,0,25],[0,0,13,215,0,1,4,46,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,3,192,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,20,3,0,0,57,0,0,2,99,0,0,1,61],[0,0,3,231,2,16,0,156,0,0,7,249,0,0,129,61,0,0,0,96,1,16,0,57,0,0,0,64,0,16,4,63],[0,0,0,0,0,1,4,45,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48,0,1,0,0,0,0,0,2],[0,0,0,0,1,0,0,50,0,0,8,204,0,0,193,61,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,8,62,0,0,97,61,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,8,198,0,0,97,61],[0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,1,0,0,0,1,0,29,0,0,3,134,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,197,0,0,97,61,0,0,0,1,2,0,0,41,0,0,3,232,2,32,0,57,0,0,0,0,1,1,4,59],[0,0,0,0,1,33,0,75,0,0,8,198,0,0,33,61,0,0,3,136,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,10,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,137,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,9,2,0,0,57,0,0,0,0,3,2,4,26,0,0,3,138,3,48,1,151],[0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,3,139,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,8,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,3,140,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,7,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,141,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57],[13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27,0,0,3,142,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,27],[0,0,3,143,1,0,0,65,0,0,0,0,0,16,4,57,0,0,3,119,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,3,119,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199],[0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,3,130,1,16,1,151,0,0,0,4,2,0,0,57,0,0,0,0,3,2,4,26],[0,0,3,138,3,48,1,151,0,0,0,0,1,19,1,159,0,0,0,0,0,18,4,27,0,0,0,2,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,3,144,2,32,1,151,0,0,0,2,3,0,3,103,0,0,0,0,3,3,4,59],[0,0,0,224,3,48,2,112,0,0,0,0,2,50,1,159,0,0,0,0,0,33,4,27,0,0,3,134,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,3,119,2,16,0,156,0,0,3,119,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,3,135,1,16,1,199,0,0,128,11,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,8,197,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,5,2,0,0,57],[0,0,0,0,0,18,4,27,0,0,0,11,1,0,0,57,0,0,0,0,2,0,4,22,0,0,0,0,0,33,4,27],[0,0,0,0,0,1,4,45,0,0,0,0,0,1,4,47,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,17,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48],[0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48,0,8,0,0,0,0,0,2,0,0,0,0,1,0,4,20],[0,1,0,0,0,1,0,29,0,0,0,64,5,0,4,61,0,0,3,232,1,80,0,156,0,0,10,130,0,0,129,61],[0,0,0,160,1,80,0,57,0,0,0,64,0,16,4,63,0,0,0,128,1,80,0,57,0,0,3,146,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,96,1,80,0,57,0,0,3,147,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,64,1,80,0,57,0,0,3,148,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,122,1,0,0,57],[0,0,0,0,9,21,4,54,0,0,3,149,1,0,0,65,0,0,0,0,0,25,4,53,0,3,128,16,0,0,0,61],[0,0,0,0,3,0,0,25,0,8,0,0,0,5,0,29,0,6,0,0,0,3,0,29,0,0,3,119,1,144,0,156],[0,0,3,119,4,0,0,65,0,0,0,0,9,4,128,25,0,0,0,64,1,144,2,16,0,0,0,0,2,5,4,51],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,0,3,2,0,0,41,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,10,138,0,0,97,61,0,0,0,64,2,0,4,61,0,0,0,0,1,1,4,59],[0,7,0,0,0,1,0,29,0,0,0,8,6,0,0,41,0,0,0,0,1,6,4,51,0,0,0,0,3,1,0,75],[0,0,9,9,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,35,0,25,0,0,0,32,3,48,0,57],[0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,0,4,19,0,75],[0,0,9,2,0,0,65,61,0,0,0,0,3,33,0,25,0,0,0,0,0,3,4,53,0,0,3,119,3,32,0,156],[0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,3,119,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,2,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,5,3,0,25,0,0,0,32,5,0,128,57],[0,0,0,5,4,80,2,114,0,0,9,42,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,70,0,75,0,0,9,35,0,0,65,61,0,0,0,31,5,80,1,144,0,0,9,56,0,0,97,61],[0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207],[0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,64,10,0,4,61,0,0,0,1,2,32,1,144],[0,0,10,140,0,0,97,61,0,0,0,0,2,0,4,51,0,0,0,32,12,160,0,57,0,0,0,8,6,0,0,41],[0,0,0,0,1,6,4,51,0,0,0,0,3,1,0,75,0,0,9,75,0,0,97,61,0,0,0,0,3,0,0,25],[0,0,0,0,4,195,0,25,0,0,0,32,3,48,0,57,0,0,0,0,5,99,0,25,0,0,0,0,5,5,4,51],[0,0,0,0,0,84,4,53,0,0,0,0,4,19,0,75,0,0,9,68,0,0,65,61,0,0,0,7,2,32,1,79],[0,0,0,0,3,193,0,25,0,0,0,0,0,35,4,53,0,0,0,32,3,16,0,57,0,0,0,0,0,58,4,53],[0,0,0,95,3,16,0,57,0,0,0,32,1,0,0,138,0,0,0,0,3,19,1,111,0,0,0,0,13,163,0,25],[0,0,0,0,3,61,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,3,127,4,208,0,156],[0,0,10,130,0,0,33,61,0,0,0,1,3,48,1,144,0,0,10,130,0,0,193,61,0,0,0,64,0,208,4,63],[0,0,0,12,11,0,0,57,0,0,0,0,3,11,4,26,0,0,3,127,4,48,0,156,0,0,10,130,0,0,33,61],[0,0,0,1,4,48,0,57,0,0,0,0,0,75,4,27,0,0,0,0,0,176,4,53,0,0,3,151,3,48,0,65],[0,0,0,0,0,35,4,27,0,0,0,0,4,11,4,26,0,0,0,0,3,4,0,75,0,0,10,134,0,0,97,61],[0,0,0,1,3,0,0,57,0,0,0,1,6,64,0,140,0,0,9,132,0,0,97,61,0,0,0,0,3,11,4,26],[0,0,0,0,4,99,0,75,0,0,10,124,0,0,161,61,0,0,0,1,4,96,0,138,0,0,0,1,5,64,2,112],[0,0,0,0,7,83,0,75,0,0,10,124,0,0,161,61,0,0,3,151,7,96,0,65,0,0,0,0,9,7,4,26],[0,0,0,0,0,176,4,53,0,0,3,151,6,80,0,65,0,0,0,0,8,6,4,26,0,0,0,0,9,137,0,75],[0,0,9,132,0,0,161,61,0,0,0,0,0,135,4,27,0,0,0,0,3,11,4,26,0,0,0,0,3,83,0,75],[0,0,10,124,0,0,161,61,0,0,0,0,0,38,4,27,0,0,0,2,3,64,0,140,0,0,0,0,6,5,0,25],[0,0,9,107,0,0,129,61,0,0,0,0,3,11,4,26,0,0,0,0,2,3,0,75,0,0,10,134,0,0,97,61],[0,0,0,1,2,48,0,138,0,0,0,0,2,35,1,112,0,0,9,144,0,0,193,61,0,0,0,13,2,0,0,57],[0,0,0,0,3,2,4,26,0,0,3,127,4,48,1,151,0,0,3,127,5,64,0,156,0,0,10,134,0,0,97,61],[0,0,3,152,3,48,1,151,0,0,0,1,4,64,0,57,0,0,0,0,3,52,1,159,0,0,0,0,0,50,4,27],[0,5,0,0,0,12,0,29,0,7,0,0,0,11,0,29,0,0,3,153,2,0,0,65,0,0,0,0,0,45,4,53],[0,0,0,4,2,208,0,57,0,0,0,32,3,0,0,57,0,2,0,0,0,3,0,29,0,0,0,0,0,50,4,53],[0,0,0,0,2,10,4,51,0,0,0,36,3,208,0,57,0,0,0,0,0,35,4,53,0,0,0,68,3,208,0,57],[0,0,0,0,4,2,0,75,0,0,9,166,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,52,0,25],[0,0,0,32,4,64,0,57,0,0,0,0,6,164,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53],[0,0,0,0,5,36,0,75,0,0,9,159,0,0,65,61,0,8,0,0,0,10,0,29,0,0,0,0,3,50,0,25],[0,0,0,0,0,3,4,53,0,0,0,31,2,32,0,57,0,0,0,0,1,18,1,111,0,0,3,119,2,208,0,156],[0,0,3,119,4,0,0,65,0,0,0,0,2,4,0,25,0,0,0,0,2,13,64,25,0,0,0,64,2,32,2,16],[0,0,0,68,1,16,0,57,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57,0,4,0,0,0,13,0,29],[13,214,13,204,0,0,4,15,0,0,0,4,12,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,5,5,64,2,114,0,0,9,207,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,124,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,9,199,0,0,65,61,0,0,0,31,6,64,1,144],[0,0,0,7,11,0,0,41,0,0,0,5,9,0,0,41,0,0,9,224,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,7,81,3,79,0,0,0,0,5,92,0,25,0,0,0,3,6,96,2,16,0,0,0,0,8,5,4,51],[0,0,0,0,8,104,1,207,0,0,0,0,8,104,2,47,0,0,0,0,7,7,4,59,0,0,1,0,6,96,0,137],[0,0,0,0,7,103,2,47,0,0,0,0,6,103,1,207,0,0,0,0,6,134,1,159,0,0,0,0,0,101,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,0,8,10,0,0,41],[0,0,10,172,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,194,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,3,127,4,16,0,156],[0,0,10,130,0,0,33,61,0,0,0,1,2,32,1,144,0,0,10,130,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,2,48,0,140,0,0,10,138,0,0,65,61,0,0,0,6,3,0,0,41,0,0,0,2,2,48,0,140],[0,0,0,1,3,48,0,57,0,0,0,0,5,10,0,25,0,0,8,229,0,0,161,61,0,0,0,0,2,11,4,26],[0,0,0,0,3,2,0,75,0,0,10,207,0,0,97,61,0,0,3,154,3,32,0,65,0,0,0,0,4,3,4,26],[0,0,3,151,5,0,0,65,0,0,0,0,0,69,4,27,0,0,0,0,0,176,4,53,0,0,0,0,0,3,4,27],[0,0,0,1,3,32,0,138,0,0,0,0,0,59,4,27,0,0,0,2,2,48,0,140,0,0,10,55,0,0,65,61],[0,0,0,1,6,0,0,57,0,0,3,157,2,0,0,65,0,0,0,0,7,0,0,25,0,0,0,0,5,0,0,25],[0,0,0,2,8,112,0,57,0,0,0,0,4,56,0,75,0,0,0,0,4,6,0,25,0,0,10,19,0,0,129,61],[0,0,3,155,4,112,0,65,0,0,0,0,4,4,4,26,0,0,3,156,7,112,0,65,0,0,0,0,7,7,4,26],[0,0,0,0,4,71,0,75,0,0,0,0,4,6,0,25,0,0,0,0,4,8,64,25,0,0,0,0,6,67,0,75],[0,0,10,124,0,0,161,61,0,0,3,151,6,64,0,65,0,0,0,0,7,83,0,75,0,0,10,124,0,0,161,61],[0,0,0,0,7,6,4,26,0,0,0,0,0,176,4,53,0,0,3,151,8,80,0,65,0,0,0,0,5,8,4,26],[0,0,0,0,9,87,0,75,0,0,10,52,0,0,161,61,0,0,0,0,0,120,4,27,0,0,0,0,3,11,4,26],[0,0,0,0,3,67,0,75,0,0,10,124,0,0,161,61,0,0,0,0,0,86,4,27,0,0,0,0,3,4,0,75],[0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25,0,0,3,157,5,64,1,151,0,0,0,0,6,5,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,2,32,25,0,0,3,157,5,80,0,156,0,0,0,0,6,3,192,25],[0,0,0,0,3,6,0,75,0,0,10,134,0,0,193,61,0,0,0,0,3,11,4,26,0,0,0,1,7,64,2,16],[0,0,0,1,6,112,1,191,0,0,0,0,5,54,0,75,0,0,0,0,5,4,0,25,0,0,10,8,0,0,65,61],[0,0,0,1,2,0,0,138,0,0,0,0,2,35,0,75,0,0,10,134,0,0,97,61,0,0,0,1,2,48,0,57],[0,0,0,0,2,50,1,112,0,0,10,67,0,0,193,61,0,0,0,13,2,0,0,57,0,0,0,0,3,2,4,26],[0,0,3,127,4,48,1,151,0,0,0,1,4,64,0,138,0,0,3,127,5,64,0,156,0,0,10,134,0,0,33,61],[0,0,3,152,3,48,1,151,0,0,0,0,3,52,1,159,0,0,0,0,0,50,4,27,0,0,0,0,3,0,4,20],[0,0,0,1,2,48,0,107,0,0,10,213,0,0,161,61,0,7,0,0,0,3,0,29,0,0,0,0,2,10,4,51],[0,0,0,0,3,2,0,75,0,0,10,82,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,4,19,0,25],[0,0,0,32,3,48,0,57,0,0,0,0,5,163,0,25,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53],[0,0,0,0,4,35,0,75,0,0,10,75,0,0,65,61,0,0,0,0,3,18,0,25,0,0,0,0,0,3,4,53],[0,0,3,119,4,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16],[0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,150,1,16,1,199,0,0,128,16,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,10,138,0,0,97,61,0,0,0,7,3,0,0,41,0,0,0,1,2,48,0,105],[0,0,0,0,5,1,4,59,0,0,0,64,1,0,4,61,0,0,0,0,0,33,4,53,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,3,119,4,0,0,65,0,0,0,0,2,4,128,25,0,0,3,119,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,3,160,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57,0,0,3,161,4,0,0,65],[13,214,13,204,0,0,4,15,0,0,0,1,1,32,1,144,0,0,10,138,0,0,97,61,0,0,0,0,0,1,4,45],[0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57,0,0,0,4,0,16,4,63],[0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,10,127,0,0,1,61,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,17,1,0,0,57,0,0,10,127,0,0,1,61,0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48],[0,0,0,31,2,48,1,143,0,0,0,5,4,48,2,114,0,0,10,152,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,106,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,10,144,0,0,65,61],[0,0,0,0,5,2,0,75,0,0,10,167,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79],[0,0,0,0,4,74,0,25,0,0,0,3,2,32,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,37,1,207],[0,0,0,0,5,37,2,47,0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47],[0,0,0,0,1,33,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,3,119,1,0,0,65],[0,0,3,119,2,160,0,156,0,0,0,0,10,1,128,25,0,0,0,64,1,160,2,16,0,0,10,204,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,10,185,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,10,177,0,0,65,61,0,0,0,0,6,4,0,75,0,0,10,200,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,119,1,0,0,65,0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,13,216,0,1,4,48,0,0,0,68,2,16,0,57],[0,0,3,198,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,1,3,0,0,57],[0,0,10,218,0,0,1,61,0,0,0,68,2,16,0,57,0,0,3,158,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,18,3,0,0,57,0,0,0,0,0,50,4,53,0,0,3,131,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,2,3,0,0,41,0,0,0,0,0,50,4,53],[0,0,3,119,2,0,0,65,0,0,3,119,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,3,159,1,16,1,199,0,0,13,216,0,1,4,48,0,1,0,0,0,0,0,2,0,0,0,64,7,0,4,61],[0,0,3,153,2,0,0,65,0,0,0,0,0,39,4,53,0,0,0,4,2,112,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,0,2,1,4,51,0,0,0,36,3,112,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,3,112,0,57,0,0,0,0,4,2,0,75,0,0,10,251,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,20,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,10,244,0,0,65,61,0,0,0,0,1,50,0,25],[0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,32,2,0,0,138,0,0,0,0,1,33,1,111],[0,0,3,119,2,0,0,65,0,0,3,119,3,112,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,7,64,25],[0,0,0,64,3,48,2,16,0,0,0,68,1,16,0,57,0,0,3,119,4,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,3,119,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57],[0,1,0,0,0,7,0,29,13,214,13,204,0,0,4,15,0,0,0,1,10,0,0,41,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,11,37,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,11,29,0,0,65,61,0,0,0,0,7,5,0,75,0,0,11,52,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,11,70,0,0,97,61],[0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,162,0,25,0,0,0,0,2,33,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,3,127,4,16,0,156,0,0,11,105,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,11,105,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,11,111,0,0,65,61,0,0,0,0,0,1,4,45,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,11,83,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,11,75,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,11,98,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,119,1,0,0,65,0,0,3,119,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159],[0,0,13,216,0,1,4,48,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48,0,0,0,0,1,0,0,25],[0,0,13,216,0,1,4,48,0,0,0,64,2,0,4,61,0,0,3,233,1,32,0,156,0,0,11,170,0,0,129,61],[0,0,0,192,1,32,0,57,0,0,0,64,0,16,4,63,0,0,0,160,1,32,0,57,0,0,3,163,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,128,3,32,0,57,0,0,3,164,1,0,0,65,0,0,0,0,0,19,4,53],[0,0,0,96,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53],[0,0,0,32,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,135,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,64,2,0,4,61,0,0,3,162,3,32,0,156,0,0,11,170,0,0,33,61,0,0,0,192,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,160,3,32,0,57,0,0,3,165,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,128,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,96,3,32,0,57,0,0,0,0,0,19,4,53],[0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,32,3,32,0,57,0,0,0,0,0,19,4,53],[0,0,0,136,1,0,0,57,0,0,0,0,0,18,4,53,0,0,0,64,1,0,4,61,0,0,3,162,2,16,0,156],[0,0,11,170,0,0,33,61,0,0,0,192,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,160,2,16,0,57],[0,0,3,166,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,128,2,16,0,57,0,0,3,164,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,96,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,64,2,16,0,57],[0,0,0,0,0,50,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,137,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,0,0,1,4,45,0,0,3,199,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65,0,0,13,216,0,1,4,48],[0,5,0,0,0,0,0,2,0,0,0,64,1,0,4,61,0,0,3,231,2,16,0,156,0,0,13,75,0,0,129,61],[0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63,0,0,3,172,2,0,0,65,0,0,0,0,2,33,4,54],[0,0,0,64,4,0,4,61,0,0,3,173,3,64,0,156,0,0,13,75,0,0,33,61,0,0,0,128,3,64,0,57],[0,0,0,64,0,48,4,63,0,0,0,96,3,64,0,57,0,0,3,174,5,0,0,65,0,0,0,0,0,83,4,53],[0,0,0,64,3,64,0,57,0,0,3,175,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,32,3,64,0,57],[0,0,3,176,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,65,7,0,0,57,0,0,0,0,0,116,4,53],[0,0,0,64,3,16,0,57,0,0,3,177,5,0,0,65,0,0,0,0,0,83,4,53,0,0,0,0,0,66,4,53],[0,0,0,64,8,0,4,61,0,0,3,171,4,128,0,156,0,0,13,75,0,0,33,61,0,0,0,96,4,128,0,57],[0,0,0,64,0,64,4,63,0,0,3,178,4,0,0,65,0,0,0,0,9,72,4,54,0,0,0,64,4,0,4,61],[0,0,3,173,5,64,0,156,0,0,13,75,0,0,33,61,0,0,0,128,5,64,0,57,0,0,0,64,0,80,4,63],[0,0,0,96,5,64,0,57,0,0,3,174,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,64,5,64,0,57],[0,0,3,179,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,32,5,64,0,57,0,0,3,180,6,0,0,65],[0,0,0,0,0,101,4,53,0,5,0,0,0,7,0,29,0,0,0,0,0,116,4,53,0,0,0,64,6,128,0,57],[0,0,3,181,5,0,0,65,0,1,0,0,0,6,0,29,0,0,0,0,0,86,4,53,0,0,0,0,0,73,4,53],[0,0,0,0,2,2,4,51,0,0,0,0,84,2,4,52,0,0,0,65,4,64,0,140,0,0,13,73,0,0,193,61],[0,0,0,65,4,32,0,57,0,0,0,0,4,4,4,51,0,0,0,255,4,64,1,143,0,0,0,27,6,64,0,138],[0,0,0,1,6,96,0,140,0,0,13,73,0,0,33,61,0,3,0,0,0,9,0,29,0,4,0,0,0,8,0,29],[0,0,0,0,3,3,4,51,0,2,0,0,0,3,0,29,0,0,0,0,1,1,4,51,0,0,0,0,3,5,4,51],[0,0,0,64,2,32,0,57,0,0,0,0,2,2,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57],[0,0,0,0,0,38,4,53,0,0,0,64,2,80,0,57,0,0,0,0,0,50,4,53,0,0,0,32,2,80,0,57],[0,0,0,0,0,66,4,53,0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156],[0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,12,32,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,12,25,0,0,65,61],[0,0,0,0,6,5,0,75,0,0,12,46,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16],[0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79],[0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207],[0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85],[0,0,0,1,2,32,1,144,0,0,0,4,5,0,0,41,0,0,0,3,2,0,0,41,0,0,13,81,0,0,97,61],[0,0,0,0,1,0,4,51,0,0,0,2,1,16,1,79,0,0,3,130,1,16,1,152,0,0,13,73,0,0,193,61],[0,0,0,0,1,2,4,51,0,0,0,0,50,1,4,52,0,0,0,65,2,32,0,140,0,0,13,73,0,0,193,61],[0,0,0,65,2,16,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143,0,0,0,27,4,32,0,138],[0,0,0,1,4,64,0,140,0,0,13,73,0,0,33,61,0,0,0,1,4,0,0,41,0,0,0,0,4,4,4,51],[0,3,0,0,0,4,0,29,0,0,0,0,4,5,4,51,0,0,0,0,3,3,4,51,0,0,0,64,1,16,0,57],[0,0,0,0,1,1,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,22,4,53],[0,0,0,64,1,80,0,57,0,0,0,0,0,49,4,53,0,0,0,32,1,80,0,57,0,0,0,0,0,33,4,53],[0,0,0,0,0,69,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199],[0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,12,111,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,12,104,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,12,125,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,13,110,0,0,97,61,0,0,0,0,1,0,4,51,0,0,0,3,1,16,1,79,0,0,3,130,1,16,1,152],[0,0,13,73,0,0,193,61,0,0,0,64,1,0,4,61,0,0,3,171,2,16,0,156,0,0,0,5,7,0,0,41],[0,0,13,75,0,0,33,61,0,0,0,96,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,0,5,1,4,54],[0,0,0,64,2,0,4,61,0,0,3,173,3,32,0,156,0,0,13,75,0,0,33,61,0,0,0,128,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,96,3,32,0,57,0,0,3,174,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,64,3,32,0,57,0,0,3,183,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,32,4,32,0,57],[0,0,3,184,6,0,0,65,0,0,0,0,0,100,4,53,0,0,0,0,0,114,4,53,0,0,0,64,6,16,0,57],[0,0,3,185,7,0,0,65,0,0,0,0,0,118,4,53,0,0,0,0,0,37,4,53,0,0,0,0,5,2,4,51],[0,0,0,65,5,80,0,140,0,0,13,73,0,0,193,61,0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51],[0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138,0,0,0,1,5,80,0,140,0,0,13,73,0,0,33,61],[0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51,0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61],[0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53,0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53],[0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53,0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53],[0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20,0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199,0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,12,209,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,12,202,0,0,65,61,0,0,0,0,6,5,0,75,0,0,12,223,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,13,139,0,0,97,61,0,0,0,0,1,0,4,51],[0,0,3,130,1,16,1,151,0,0,3,185,1,16,0,156,0,0,13,73,0,0,193,61,0,0,0,64,1,0,4,61],[0,0,3,171,2,16,0,156,0,0,0,5,7,0,0,41,0,0,13,75,0,0,33,61,0,0,0,96,2,16,0,57],[0,0,0,64,0,32,4,63,0,0,3,186,2,0,0,65,0,0,0,0,5,33,4,54,0,0,0,64,2,0,4,61],[0,0,3,173,3,32,0,156,0,0,13,75,0,0,33,61,0,0,0,128,3,32,0,57,0,0,0,64,0,48,4,63],[0,0,0,96,3,32,0,57,0,0,3,187,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,64,3,32,0,57],[0,0,3,188,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,32,4,32,0,57,0,0,3,189,6,0,0,65],[0,0,0,0,0,100,4,53,0,0,0,0,0,114,4,53,0,0,0,0,0,37,4,53,0,0,0,64,5,16,0,57],[0,0,0,0,0,5,4,53,0,0,0,0,5,2,4,51,0,0,0,65,5,80,0,140,0,0,13,73,0,0,193,61],[0,0,0,65,2,32,0,57,0,0,0,0,2,2,4,51,0,0,0,255,2,32,1,143,0,0,0,27,5,32,0,138],[0,0,0,1,5,80,0,140,0,0,13,73,0,0,33,61,0,0,0,0,1,1,4,51,0,0,0,0,4,4,4,51],[0,0,0,0,3,3,4,51,0,0,0,64,5,0,4,61,0,0,0,96,6,80,0,57,0,0,0,0,0,54,4,53],[0,0,0,64,3,80,0,57,0,0,0,0,0,67,4,53,0,0,0,32,3,80,0,57,0,0,0,0,0,35,4,53],[0,0,0,0,0,21,4,53,0,0,0,0,0,0,4,53,0,0,3,119,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,3,119,3,32,0,156,0,0,0,0,2,1,128,25,0,0,3,119,3,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,1,80,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,3,182,1,16,1,199],[0,0,0,1,2,0,0,57,13,214,13,209,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,3,119,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114,0,0,13,51,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75,0,0,13,44,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,13,65,0,0,97,61,0,0,0,3,5,80,2,16,0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159],[0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,13,168,0,0,97,61,0,0,0,0,1,0,4,51,0,0,3,130,1,16,1,152,0,0,13,73,0,0,193,61],[0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,13,216,0,1,4,48,0,0,3,199,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,3,200,1,0,0,65],[0,0,13,216,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,13,94,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,13,86,0,0,65,61,0,0,0,0,6,4,0,75,0,0,13,196,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,13,196,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,13,123,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,13,115,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,13,138,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,13,196,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,13,152,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,13,144,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,13,167,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,13,196,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,13,181,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,13,173,0,0,65,61,0,0,0,0,6,4,0,75,0,0,13,196,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,119,1,0,0,65,0,0,3,119,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,13,216,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,13,207,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,13,212,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,13,214,0,0,4,50,0,0,13,215,0,1,4,46],[0,0,13,216,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[224,63,225,119,187,5,10,64,234,27,62,205,100,18,26,63,160,99,169,75,109,64,75,47,69,198,70,151,85,94,254,14],[197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112],[153,58,4,183,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,160,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[142,148,254,212,66,57,235,35,20,171,122,64,99,69,230,197,168,240,204,237,243,182,0,222,61,0,78,103,44,51,171,244],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[105,110,32,100,101,108,101,103,97,116,101,32,99,97,108,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[66,203,177,92,205,195,202,214,38,107,14,122,8,192,69,75,35,191,41,220,45,247,75,111,60,32,158,147,54,70,91,209],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0],[25,202,228,98,154,45,215,137,0,54,208,209,246,168,39,66,132,91,119,139,113,132,227,141,91,235,253,76,206,59,24,30],[166,174,10,172,21,139,45,92,154,156,146,133,116,52,25,214,42,50,246,114,122,100,9,85,228,206,142,228,21,3,199,132],[255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[120,119,167,151,254,109,202,67,33,243,63,217,84,20,218,7,154,183,142,105,141,118,21,20,192,28,237,146,17,175,38,126],[254,23,59,151,237,154,162,99,35,108,82,250,62,179,52,208,119,65,173,217,94,151,45,23,53,45,118,129,107,74,174,163],[154,138,5,146,172,137,197,173,59,198,223,130,36,193,123,72,89,118,245,151,223,16,78,226,13,13,244,21,36,31,103,11],[121,107,137,185,22,68,188,152,205,147,149,142,76,144,56,39,93,98,33,131,226,90,197,175,8,204,107,93,149,83,145,50],[147,139,95,50,153,161,243,177,142,69,133,100,239,187,149,7,51,34,96,20,238,206,38,250,225,144,18,216,80,180,141,131],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,95],[116,104,101,32,105,110,100,117,115,116,114,121,39,115,32,115,116,97,110,100,97,114,100,46,46,46,0,0,0,0,0,0],[32,105,110,100,117,115,116,114,121,46,32,76,111,114,101,109,32,73,112,115,117,109,32,104,97,115,32,98,101,101,110,32],[32,111,102,32,116,104,101,32,112,114,105,110,116,105,110,103,32,97,110,100,32,116,121,112,101,115,101,116,116,105,110,103],[76,111,114,101,109,32,73,112,115,117,109,32,105,115,32,115,105,109,112,108,121,32,100,117,109,109,121,32,116,101,120,116],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,199],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0],[98,248,75,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,198],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,201],[223,105,102,201,113,5,28,61,84,236,89,22,38,6,83,20,147,165,20,4,160,2,132,47,86,0,157,126,92,244,168,200],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[83,111,109,101,32,101,114,114,111,114,32,109,101,115,115,97,103,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[133,189,45,42,160,229,82,140,202,50,72,223,177,233,146,208,17,58,85,56,2,215,146,79,223,4,154,233,237,29,91,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,63],[97,97,97,97,97,97,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97],[97,97,97,97,97,97,97,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,97,97,97,97,97,97,97,97,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[102,3,194,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0],[72,101,97,112,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,109,111,100,105,102,105,101,100,0,0,0,0,0],[171,37,105,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,159],[20,67,19,57,18,139,210,95,44,127,147,186,166,17,227,103,71,32,72,117,127,74,214,127,109,113,165,202,13,165,80,245],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,127],[28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[70,234,191,53,104,3,40,226,110,244,87,156,175,138,235,44,249,236,224,93,191,103,164,243,209,242,140,123,29,14,53,70],[81,228,219,187,206,186,222,105,90,63,15,223,16,190,184,181,248,63,218,22,30,26,49,5,161,76,65,22,139,243,220,224],[0,0,0,0,0,0,0,0,0,0,0,0,127,139,59,4,191,52,97,143,74,23,35,251,169,107,93,178,17,39,154,43],[224,104,47,212,162,96,50,175,255,59,24,5,58,12,51,210,166,196,101,192,225,156,177,228,193,14,176,169,73,242,130,124],[11,219,95,10,199,157,26,126,253,194,85,243,153,160,69,3,140,27,67,62,157,6,193,177,171,213,138,95,202,171,51,241],[196,108,220,80,166,111,77,7,198,233,161,39,167,39,126,136,47,178,27,207,181,176,104,242,181,140,127,114,131,153,59,121],[0,0,0,0,0,0,0,0,0,0,0,0,8,101,167,125,77,104,199,227,205,210,25,212,49,207,238,146,113,144,80,116],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0],[46,56,93,100,142,59,225,148,212,95,187,31,114,41,239,16,197,183,238,28,124,48,20,90,164,221,249,56,14,171,90,3],[155,55,233,20,69,233,43,20,35,53,72,37,170,51,216,65,216,60,172,253,216,149,211,22,174,136,218,188,49,115,105,150],[0,0,0,0,0,0,0,0,0,0,0,0,158,21,153,225,16,206,239,79,21,232,238,112,106,217,205,74,91,142,198,237],[221,105,233,149,15,82,221,220,188,103,81,253,187,105,73,120,124,193,184,74,196,2,10,176,97,126,200,173,149,14,85,74],[27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[64,104,245,181,230,196,180,66,232,63,203,123,98,144,82,14,187,94,7,124,209,13,59,216,108,244,49,202,75,100,1,98],[176,9,134,216,187,82,238,122,203,6,202,191,166,194,192,153,216,144,76,124,141,86,112,122,38,125,219,175,215,174,208,112],[0,0,0,0,0,0,0,0,0,0,0,0,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[102,97,105,108,101,100,32,116,114,97,110,115,102,101,114,32,99,97,108,108,0,0,0,0,0,0,0,0,0,0,0,0],[102,97,105,108,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[115,101,110,100,105,110,103,32,108,49,32,109,101,115,115,97,103,101,115,32,116,101,115,116,32,115,104,111,117,108,100,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[104,101,97,112,32,116,101,115,116,32,115,104,111,117,108,100,32,102,97,105,108,101,100,0,0,0,0,0,0,0,0,0],[72,101,97,112,32,115,104,111,117,108,100,32,110,111,116,32,98,101,32,101,109,112,116,121,0,0,0,0,0,0,0,0],[119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,119,55,221,230],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,100,13,14],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,198,249,104,131],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,198,249,104,132],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,230,246,42,184],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,251,56,170,86],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,175,100,13,15],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,190,139,17,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,78,143,142],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,78,143,143],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,58,4,183],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,171,37,105,15],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,119,55,221,231],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,213,148,97],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,64,160,80],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,48,143,14],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,48,143,15],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,94,254,75,180],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,102,3,194,241],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,64,160,81],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,154,227,236],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,132,79,187],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,132,79,188],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,187,215,72],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,208,93,63],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,216,172,97],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[84,101,115,116,32,109,101,115,115,97,103,101,32,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,128,0,0,0,0,0,0,0,0],[62,169,138,246,227,81,65,251,202,204,23,36,225,79,93,118,185,181,142,65,246,195,93,14,138,226,226,4,230,102,149,235],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,160],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,96],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,64],[214,157,133,29,132,62,228,160,250,200,14,30,42,137,20,209,16,252,193,75,95,47,89,133,35,162,110,88,69,252,146,234]],"default_account_code":[[0,4,0,0,0,0,0,2,0,12,0,0,0,0,0,2,0,0,0,0,3,1,0,25,0,0,0,96,7,48,2,112],[0,0,5,2,6,112,1,151,0,3,0,0,0,97,3,85,0,2,0,0,0,1,3,85,0,0,5,2,0,112,1,157],[0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63,0,0,0,1,2,32,1,144,0,0,0,44,0,0,193,61],[0,0,0,4,2,96,0,140,0,0,0,52,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,5,4,3,32,0,156,0,0,0,68,0,0,161,61,0,0,5,5,3,32,0,156,0,0,0,150,0,0,97,61],[0,0,5,6,3,32,0,156,0,0,0,197,0,0,97,61,0,0,5,7,2,32,0,156,0,0,0,54,0,0,193,61],[0,0,0,4,2,96,0,138,0,0,0,32,3,32,0,140,0,0,1,39,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,1,1,4,59,0,0,5,10,3,16,0,156,0,0,1,39,0,0,33,61,0,0,0,0,1,18,0,73],[0,0,5,11,2,0,0,65,0,0,2,96,3,16,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,0,5,11,1,16,1,151,0,0,0,0,4,1,0,75,0,0,0,0,2,0,160,25,0,0,5,11,1,16,0,156],[0,0,0,0,2,3,192,25,0,0,0,0,1,2,0,75,0,0,3,118,0,0,97,61,0,0,1,39,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,1,39,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,5,3,1,0,0,65,0,0,20,2,0,1,4,46],[0,0,0,0,1,6,0,75,0,0,3,118,0,0,97,61,0,0,0,0,1,0,4,18,0,0,5,12,1,16,1,151],[0,0,0,0,2,0,4,16,0,0,0,0,1,33,0,75,0,0,3,118,0,0,193,61,0,0,0,0,1,0,4,17],[0,0,128,1,1,16,0,140,0,0,3,118,0,0,193,61,0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,1,1,0,0,57,0,0,0,4,0,16,4,63,0,0,5,89,1,0,0,65,0,0,20,3,0,1,4,48],[0,0,5,8,3,32,0,156,0,0,1,17,0,0,97,61,0,10,0,0,0,4,0,29,0,0,5,9,2,32,0,156],[0,0,0,54,0,0,193,61,0,0,0,4,2,96,0,138,0,0,0,96,2,32,0,140,0,0,1,39,0,0,65,61],[0,0,0,68,2,16,3,112,0,0,0,0,3,2,4,59,0,0,5,10,2,48,0,156,0,0,1,39,0,0,33,61],[0,0,0,4,4,48,0,57,0,0,0,0,5,70,0,73,0,0,5,11,2,0,0,65,0,0,2,96,7,80,0,140],[0,0,0,0,7,0,0,25,0,0,0,0,7,2,64,25,0,0,5,11,8,80,1,151,0,0,0,0,9,8,0,75],[0,0,0,0,2,0,160,25,0,0,5,11,8,128,0,156,0,0,0,0,2,7,192,25,0,0,0,0,2,2,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140,0,0,3,118,0,0,193,61],[0,0,0,0,2,0,4,18,0,0,5,12,7,32,1,151,0,0,0,0,2,0,4,16,0,0,0,0,7,39,0,75],[0,0,3,118,0,0,193,61,0,0,2,36,3,48,0,57,0,0,0,0,7,49,3,79,0,0,0,0,7,7,4,59],[0,0,0,31,5,80,0,138,0,0,5,11,8,0,0,65,0,0,0,0,9,87,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,8,128,25,0,0,5,11,5,80,1,151,0,0,5,11,10,112,1,151,0,0,0,0,11,90,0,75],[0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63,0,0,5,11,5,80,0,156,0,0,0,0,8,9,192,25],[0,0,0,0,5,8,0,75,0,0,1,39,0,0,193,61,0,0,0,0,5,71,0,25,0,0,0,0,4,81,3,79],[0,0,0,0,4,4,4,59,0,0,5,10,7,64,0,156,0,0,1,39,0,0,33,61,0,0,0,0,7,70,0,73],[0,0,0,32,5,80,0,57,0,0,5,11,8,0,0,65,0,0,0,0,9,117,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,8,32,25,0,0,5,11,7,112,1,151,0,0,5,11,10,80,1,151,0,0,0,0,11,122,0,75],[0,0,0,0,8,0,128,25,0,0,0,0,7,122,1,63,0,0,5,11,7,112,0,156,0,0,0,0,8,9,192,25],[0,0,0,0,7,8,0,75,0,0,1,39,0,0,193,61,0,0,0,3,7,64,0,140,0,0,2,87,0,0,33,61],[0,0,5,16,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,58,1,0,0,57,0,0,0,164,0,16,4,63,0,0,5,50,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,5,51,1,0,0,65,0,0,2,103,0,0,1,61,0,0,0,4,2,96,0,138,0,0,0,96,2,32,0,140],[0,0,1,39,0,0,65,61,0,0,0,68,2,16,3,112,0,0,0,0,3,2,4,59,0,0,5,10,2,48,0,156],[0,0,1,39,0,0,33,61,0,0,0,4,2,48,0,57,0,0,0,0,5,38,0,73,0,0,5,11,4,0,0,65],[0,0,2,96,8,80,0,140,0,0,0,0,8,0,0,25,0,0,0,0,8,4,64,25,0,0,5,11,9,80,1,151],[0,0,0,0,10,9,0,75,0,0,0,0,4,0,160,25,0,0,5,11,9,144,0,156,0,0,0,0,4,8,192,25],[0,0,0,0,4,4,0,75,0,0,1,39,0,0,193,61,0,0,0,0,4,0,4,17,0,0,128,1,4,64,0,140],[0,0,3,118,0,0,193,61,0,0,0,0,4,0,4,18,0,0,5,12,4,64,1,151,0,0,0,0,8,0,4,16],[0,0,0,0,4,132,0,75,0,0,3,118,0,0,193,61,0,0,0,68,4,48,0,57,0,0,0,0,4,65,3,79],[0,0,1,36,8,48,0,57,0,0,0,0,3,129,3,79,0,0,0,0,4,4,4,59,0,0,5,12,4,64,1,151],[0,0,0,0,3,3,4,59,0,0,5,18,9,48,0,156,0,0,1,248,0,0,65,61,0,0,5,16,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,8,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,27,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,28,1,0,0,65],[0,0,20,3,0,1,4,48,0,0,0,4,3,96,0,138,0,0,0,96,2,48,0,140,0,0,1,39,0,0,65,61],[0,0,0,68,2,16,3,112,0,0,0,0,2,2,4,59,0,0,5,10,4,32,0,156,0,0,1,39,0,0,33,61],[0,0,0,0,3,35,0,73,0,0,5,11,4,0,0,65,0,0,2,96,5,48,0,140,0,0,0,0,5,0,0,25],[0,0,0,0,5,4,64,25,0,0,5,11,3,48,1,151,0,0,0,0,6,3,0,75,0,0,0,0,4,0,160,25],[0,0,5,11,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75,0,0,1,39,0,0,193,61],[0,0,0,0,3,0,4,17,0,0,128,1,3,48,0,140,0,0,3,118,0,0,193,61,0,0,0,0,3,0,4,18],[0,0,5,12,3,48,1,151,0,0,0,0,4,0,4,16,0,0,0,0,3,67,0,75,0,0,3,118,0,0,193,61],[0,0,0,164,3,32,0,57,0,0,0,0,3,49,3,79,0,0,0,100,2,32,0,57,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,0,0,2,3,4,59,0,0,0,0,3,2,0,75,0,0,1,224,0,0,193,61],[0,0,0,0,4,0,4,21,0,0,0,12,4,64,0,138,0,0,0,32,4,64,0,201,0,0,0,0,1,0,4,20],[0,12,0,0,0,0,0,29,0,10,0,0,0,4,0,29,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,192,1,16,2,16,0,0,128,1,2,0,0,57,20,1,19,237,0,0,4,15],[0,0,0,10,3,0,0,41,0,3,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,1,5,2,0,16,1,157],[0,0,0,5,1,48,2,112,0,0,0,1,1,32,1,149,0,0,0,1,1,32,1,144,0,0,3,118,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,5,14,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,5,15,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,37,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,2,2,0,0,65],[0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,5,17,1,16,1,199],[0,0,20,3,0,1,4,48,0,0,0,4,2,96,0,138,0,0,0,96,2,32,0,140,0,0,1,39,0,0,65,61],[0,0,0,68,2,16,3,112,0,0,0,0,2,2,4,59,0,10,0,0,0,2,0,29,0,0,5,10,2,32,0,156],[0,0,1,39,0,0,33,61,0,0,0,10,2,0,0,41,0,9,0,4,0,32,0,61,0,0,0,9,2,96,0,106],[0,0,5,11,3,0,0,65,0,0,2,96,4,32,0,140,0,0,0,0,4,0,0,25,0,0,0,0,4,3,64,25],[0,0,5,11,2,32,1,151,0,0,0,0,5,2,0,75,0,0,0,0,3,0,160,25,0,0,5,11,2,32,0,156],[0,0,0,0,3,4,192,25,0,0,0,0,2,3,0,75,0,0,1,41,0,0,97,61,0,0,0,0,1,0,0,25],[0,0,20,3,0,1,4,48,0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59,0,8,0,0,0,2,0,29],[0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140,0,0,3,118,0,0,193,61,0,0,0,0,2,0,4,18],[0,0,5,12,2,32,1,151,0,0,0,0,3,0,4,16,0,7,0,0,0,3,0,29,0,0,0,0,2,50,0,75],[0,0,3,118,0,0,193,61,0,0,0,0,2,0,4,20,0,0,5,52,3,0,0,65,0,0,0,160,0,48,4,63],[0,0,0,10,3,0,0,41,0,6,1,4,0,48,0,61,0,0,0,6,1,16,3,96,0,0,0,0,1,1,4,59],[0,0,0,164,0,16,4,63,0,0,0,36,1,0,0,57,0,0,0,128,0,16,4,63,0,0,0,224,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,0,192,1,32,2,16,0,0,5,24,1,16,1,151,0,0,5,53,1,16,1,199],[0,0,128,3,2,0,0,57,0,0,0,0,3,0,0,25,0,0,0,0,4,0,0,25,0,0,0,0,5,0,0,25],[0,0,0,0,6,0,0,25,20,1,19,237,0,0,4,15,0,3,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,1,5,2,0,48,1,157,0,0,5,2,8,48,1,151,0,0,0,63,3,128,0,57],[0,0,5,54,4,48,1,151,0,0,0,64,6,0,4,61,0,0,0,0,3,100,0,25,0,0,0,0,4,67,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,5,48,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,48,4,63,0,0,0,0,7,134,4,54],[0,0,0,2,3,0,3,103,0,0,0,0,4,0,0,49,0,0,0,0,5,67,3,79,0,0,0,31,9,128,0,57],[0,0,0,5,9,144,2,114,0,0,1,107,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,183,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75,0,0,1,99,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,1,109,0,0,97,61,0,0,0,31,9,128,1,143,0,0,0,5,8,128,2,114,0,0,1,121,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25,0,0,0,0,11,177,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75],[0,0,1,113,0,0,65,61,0,0,0,0,10,9,0,75,0,0,1,136,0,0,97,61,0,0,0,5,8,128,2,16],[0,0,0,0,1,129,3,79,0,0,0,0,8,135,0,25,0,0,0,3,9,144,2,16,0,0,0,0,10,8,4,51],[0,0,0,0,10,154,1,207,0,0,0,0,10,154,2,47,0,0,0,0,1,1,4,59,0,0,1,0,9,144,0,137],[0,0,0,0,1,145,2,47,0,0,0,0,1,145,1,207,0,0,0,0,1,161,1,159,0,0,0,0,0,24,4,53],[0,0,0,1,1,32,1,144,0,0,2,77,0,0,97,61,0,0,0,8,1,0,0,107,0,0,16,183,0,0,193,61],[0,0,0,6,1,0,0,41,0,0,1,0,1,16,0,138,0,0,0,0,1,19,3,79,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,0,75,0,0,2,106,0,0,193,61,0,0,0,6,1,48,3,96,0,0,0,64,9,0,4,61],[0,0,0,0,1,1,4,59,0,0,0,128,2,16,0,140,0,8,0,0,0,9,0,29,0,0,2,161,0,0,65,61],[0,0,0,128,2,16,2,112,0,0,5,60,6,16,0,156,0,0,0,0,2,1,160,25,0,0,5,60,6,16,0,156],[0,0,0,0,6,0,0,25,0,0,0,16,6,0,32,57,0,0,0,8,7,96,1,191,0,0,5,10,8,32,0,156],[0,0,0,0,7,6,160,25,0,0,0,64,6,32,2,112,0,0,5,10,8,32,0,156,0,0,0,0,6,2,160,25],[0,0,0,4,8,112,1,191,0,0,5,2,2,96,0,156,0,0,0,0,8,7,160,25,0,0,0,32,7,96,2,112],[0,0,5,2,2,96,0,156,0,0,0,0,7,6,160,25,0,0,0,2,2,128,1,191,0,0,255,255,6,112,0,140],[0,0,0,0,2,8,160,25,0,0,0,16,6,112,2,112,0,0,0,0,6,7,160,25,0,0,0,255,6,96,0,140],[0,0,0,1,2,32,32,57,0,0,0,32,6,0,0,138,0,0,0,65,7,32,0,57,0,0,0,0,6,103,1,111],[0,0,0,0,6,105,0,25,0,0,0,0,7,150,0,75,0,0,0,0,7,0,0,25,0,0,0,1,7,0,64,57],[0,0,5,10,8,96,0,156,0,0,18,165,0,0,33,61,0,0,0,1,7,112,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,96,4,63,0,0,0,2,6,32,0,57,0,0,0,8,7,0,0,41,0,0,0,0,6,103,4,54],[0,0,0,33,7,32,0,57,0,0,0,5,7,112,2,114,0,0,1,204,0,0,97,61,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,150,0,25,0,0,0,0,9,149,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,120,0,75,0,0,1,196,0,0,65,61],[0,0,0,0,7,0,0,75,0,0,1,206,0,0,97,61,0,0,0,8,7,0,0,41,0,0,0,0,7,7,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,8,32,2,16,0,0,0,0,7,120,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,2,32,2,16,0,0,0,248,2,32,0,137,0,0,0,0,1,33,1,207,0,0,0,255,2,32,0,140],[0,0,0,0,1,0,32,25,0,0,0,8,2,0,0,41,0,0,0,33,2,32,0,57,0,0,2,178,0,0,1,61],[0,0,0,0,67,18,0,169,0,0,0,0,66,35,0,217,0,0,0,0,1,18,0,75,0,0,16,208,0,0,193,61],[0,0,0,0,4,0,4,21,0,0,0,11,4,64,0,138,0,0,0,32,4,64,0,201,0,0,0,0,1,0,4,20],[0,11,0,0,0,0,0,29,0,0,0,0,2,3,0,75,0,0,0,237,0,0,97,61,0,0,5,2,2,0,0,65],[0,0,5,2,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,192,1,16,2,16,0,0,5,13,1,16,1,199],[0,0,128,9,2,0,0,57,0,0,128,1,4,0,0,57,0,0,0,0,5,0,0,25,20,1,19,237,0,0,4,15],[0,0,0,0,3,0,4,21,0,0,0,11,3,48,0,138,0,0,0,32,3,48,0,201,0,0,0,245,0,0,1,61],[0,0,0,160,8,128,0,57,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,31,5,80,0,138],[0,0,5,11,9,0,0,65,0,0,0,0,10,88,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,128,25],[0,0,5,11,5,80,1,151,0,0,5,11,11,128,1,151,0,0,0,0,12,91,0,75,0,0,0,0,9,0,128,25],[0,0,0,0,5,91,1,63,0,0,5,11,5,80,0,156,0,0,0,0,9,10,192,25,0,0,0,0,5,9,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,2,40,0,25,0,0,0,0,5,33,3,79,0,0,0,0,8,5,4,59],[0,0,5,10,5,128,0,156,0,0,1,39,0,0,33,61,0,0,0,0,5,134,0,73,0,0,0,32,9,32,0,57],[0,0,5,11,2,0,0,65,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,2,32,25],[0,0,5,11,5,80,1,151,0,0,5,11,11,144,1,151,0,0,0,0,12,91,0,75,0,0,0,0,2,0,128,25],[0,0,0,0,5,91,1,63,0,0,5,11,5,80,0,156,0,0,0,0,2,10,192,25,0,0,0,0,2,2,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,2,0,4,20,0,0,5,2,5,32,0,156,0,0,0,187,0,0,33,61],[0,0,128,6,5,64,0,140,0,0,0,0,5,0,0,25,0,0,2,52,0,0,193,61,0,0,0,4,5,128,0,140],[0,0,0,0,5,0,0,25,0,0,2,52,0,0,65,61,0,0,0,0,10,145,3,79,0,0,0,1,5,0,0,57],[0,0,0,0,10,10,4,59,0,0,5,19,10,160,1,151,0,0,5,20,11,160,0,156,0,0,2,51,0,0,97,61],[0,0,5,21,11,160,0,156,0,0,2,51,0,0,97,61,0,0,5,22,11,160,0,156,0,0,2,51,0,0,97,61],[0,0,5,23,5,160,0,156,0,0,0,0,5,0,0,25,0,0,0,1,5,0,96,57,0,0,0,1,5,80,1,143],[0,0,0,0,10,152,0,25,0,0,0,0,6,166,0,75,0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57],[0,0,0,0,8,138,0,75,0,0,0,1,6,96,65,191,0,0,5,2,8,144,1,151,0,0,0,0,1,129,3,79],[0,0,0,0,8,3,0,75,0,0,3,99,0,0,193,61,0,0,0,1,3,96,1,144,0,0,16,208,0,0,193,61],[0,0,5,25,3,0,0,65,0,0,5,26,6,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,6,3,192,25],[0,0,0,192,2,32,2,16,0,0,5,24,2,32,1,151,0,0,0,0,2,38,1,159,0,0,0,0,3,167,0,73],[0,0,5,2,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,0,1,33,3,175,0,0,0,0,2,4,0,25],[0,0,3,110,0,0,1,61,0,0,0,0,1,6,4,51,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,5,2,3,112,0,156,0,0,0,0,7,2,128,25,0,0,0,64,2,112,2,16],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,20,3,0,1,4,48,0,0,0,0,7,81,3,79],[0,0,0,0,7,7,4,59,0,0,5,19,7,112,1,151,0,0,5,29,8,112,0,156,0,0,2,255,0,0,193,61],[0,0,0,67,4,64,0,140,0,0,3,120,0,0,33,61,0,0,5,16,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,64,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,5,47,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,48,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,5,49,1,0,0,65,0,0,20,3,0,1,4,48,0,0,0,113,2,16,0,140,0,0,3,9,0,0,193,61],[0,0,0,10,2,0,0,41,0,0,1,196,1,32,0,57,0,0,0,0,1,19,3,79,0,0,0,0,2,36,0,73],[0,0,0,35,2,32,0,138,0,0,0,0,1,1,4,59,0,0,5,11,5,0,0,65,0,0,0,0,6,33,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,5,128,25,0,0,5,11,2,32,1,151,0,0,5,11,7,16,1,151],[0,0,0,0,8,39,0,75,0,0,0,0,5,0,128,25,0,0,0,0,2,39,1,63,0,0,5,11,2,32,0,156],[0,0,0,0,5,6,192,25,0,0,0,0,2,5,0,75,0,0,1,39,0,0,193,61,0,0,0,9,1,16,0,41],[0,0,0,0,2,19,3,79,0,0,0,0,2,2,4,59,0,0,5,10,5,32,0,156,0,0,1,39,0,0,33,61],[0,0,0,0,5,36,0,73,0,0,0,32,1,16,0,57,0,0,5,11,6,0,0,65,0,0,0,0,7,81,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,6,32,25,0,0,5,11,5,80,1,151,0,0,5,11,8,16,1,151],[0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,1,39,0,0,193,61,0,0,0,0,5,18,0,26],[0,0,0,0,2,0,4,20,0,0,16,208,0,0,65,61,0,0,0,0,6,84,0,75,0,0,16,208,0,0,65,61],[0,0,5,67,6,32,0,156,0,0,6,77,0,0,65,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,5,27,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57],[0,0,4,110,0,0,1,61,0,0,5,58,2,144,0,156,0,0,18,165,0,0,33,61,0,0,0,8,6,0,0,41],[0,0,0,64,2,96,0,57,0,0,0,64,0,32,4,63,0,0,0,1,2,0,0,58,0,0,0,0,2,38,4,54],[0,0,0,0,6,80,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,98,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,7,16,2,16,0,0,5,11,8,0,0,65,0,0,0,0,1,1,0,75,0,0,0,0,8,7,192,25],[0,0,5,59,1,96,1,151,0,0,0,0,1,129,1,159,0,0,0,0,0,18,4,53,0,0,0,64,1,0,4,61],[0,0,0,6,2,0,0,41,0,0,0,96,2,32,0,138,0,0,0,0,6,35,3,79,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,3,241,0,0,65,61,0,0,0,128,7,96,2,112,0,0,5,60,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,5,60,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,5,10,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,5,10,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,5,2,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,5,2,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,129,0,25,0,0,0,0,9,24,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,5,10,10,128,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,129,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,2,237,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,181,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75],[0,0,2,229,0,0,65,61,0,0,0,0,9,0,0,75,0,0,2,239,0,0,97,61,0,0,0,0,9,1,4,51],[0,0,0,0,9,9,0,75,0,0,12,17,0,0,97,61,0,0,0,0,9,8,4,51,0,0,5,59,9,144,1,151],[0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,5,61,9,144,0,65,0,0,0,0,0,152,4,53],[0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,7,16,0,57,0,0,4,1,0,0,1,61,0,0,5,30,1,112,0,156],[0,0,3,118,0,0,97,61,0,0,5,16,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,26,1,0,0,57,0,0,0,164,0,16,4,63,0,0,5,31,1,0,0,65],[0,0,0,194,0,0,1,61,0,0,0,2,2,16,0,140,0,0,3,151,0,0,193,61,0,0,5,56,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,57,1,16,1,199,0,0,128,11,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,64,3,0,4,61],[0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140,0,0,4,122,0,0,65,61,0,0,0,128,1,64,2,112],[0,0,5,60,2,64,0,156,0,0,0,0,1,4,160,25,0,0,5,60,2,64,0,156,0,0,0,0,2,0,0,25],[0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191,0,0,5,10,6,16,0,156,0,0,0,0,5,2,160,25],[0,0,0,64,2,16,2,112,0,0,5,10,6,16,0,156,0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191],[0,0,5,2,6,32,0,156,0,0,0,0,1,5,160,25,0,0,0,32,6,32,2,112,0,0,5,2,5,32,0,156],[0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191,0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25],[0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57],[0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57,0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25],[0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,5,10,6,16,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54,0,0,0,2,1,0,3,103,0,0,0,0,2,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,3,81,0,0,97,61,0,0,0,0,8,33,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,3,73,0,0,65,61,0,0,0,0,7,0,0,75,0,0,3,83,0,0,97,61,0,0,0,0,7,3,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57,0,0,4,141,0,0,1,61,0,0,0,1,6,96,1,144],[0,0,16,208,0,0,193,61,0,0,0,0,6,167,0,73,0,0,5,2,6,96,1,151,0,0,0,0,1,97,3,223],[0,0,0,192,2,32,2,16,0,0,5,24,2,32,1,151,0,0,5,25,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,9,2,0,0,57,0,0,0,0,6,0,0,25,20,1,19,247,0,0,4,15,0,3,0,0,0,1,3,85],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,1,5,2,0,48,1,157,0,0,5,2,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,4,77,0,0,97,61,0,0,0,0,1,0,0,25,0,0,20,2,0,1,4,46],[0,0,0,4,4,80,0,57,0,0,0,0,5,65,3,79,0,0,0,0,5,5,4,59,0,9,0,0,0,5,0,29],[0,0,5,12,5,80,0,156,0,0,1,39,0,0,33,61,0,0,1,64,3,48,0,138,0,0,0,0,3,49,3,79],[0,0,0,32,4,64,0,57,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59,0,8,0,0,0,4,0,29],[0,0,0,0,3,3,4,59,0,0,5,32,4,0,0,65,0,0,0,128,0,64,4,63,0,0,5,12,2,32,1,151],[0,6,0,0,0,2,0,29,0,0,0,132,0,32,4,63,0,0,5,12,2,48,1,151,0,7,0,0,0,2,0,29],[0,0,0,164,0,32,4,63,0,0,0,0,2,0,4,20,0,0,0,9,3,0,0,41,0,0,0,4,3,48,0,140],[0,0,4,217,0,0,193,61,0,0,0,0,1,97,3,79,0,0,0,1,3,0,0,49,0,0,0,32,2,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,5,5,0,0,1,61,0,0,0,1,1,16,0,140],[0,0,4,104,0,0,193,61,0,0,5,56,1,0,0,65,0,0,0,0,0,16,4,57,0,0,5,2,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,57,1,16,1,199,0,0,128,11,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,16,244,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140],[0,0,5,45,0,0,65,61,0,0,0,128,1,64,2,112,0,0,5,60,2,64,0,156,0,0,0,0,1,4,160,25],[0,0,5,60,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191],[0,0,5,10,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112,0,0,5,10,6,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,5,2,6,32,0,156,0,0,0,0,1,5,160,25],[0,0,0,32,6,32,2,112,0,0,5,2,5,32,0,156,0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57],[0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,5,10,6,16,0,156,0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54],[0,0,0,2,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,3,223,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,3,215,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,3,225,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57],[0,0,5,64,0,0,1,61,0,0,5,58,7,16,0,156,0,0,18,165,0,0,33,61,0,0,0,64,7,16,0,57],[0,0,0,64,0,112,4,63,0,0,0,1,7,0,0,58,0,0,0,0,7,113,4,54,0,0,0,0,8,80,3,80],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,12,17,0,0,97,61,0,0,0,248,9,96,2,16],[0,0,5,11,10,0,0,65,0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,5,59,6,128,1,151],[0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53,0,0,0,64,2,32,0,138,0,0,0,0,6,35,3,79],[0,0,0,64,2,0,4,61,0,0,0,0,6,6,4,59,0,0,0,128,7,96,0,140,0,0,5,140,0,0,65,61],[0,0,0,128,7,96,2,112,0,0,5,60,8,96,0,156,0,0,0,0,7,6,160,25,0,0,5,60,8,96,0,156],[0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57,0,0,0,8,9,128,1,191,0,0,5,10,10,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112,0,0,5,10,10,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,4,10,144,1,191,0,0,5,2,7,128,0,156,0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112],[0,0,5,2,7,128,0,156,0,0,0,0,9,8,160,25,0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140],[0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112,0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140],[0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138,0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111],[0,0,0,0,8,130,0,25,0,0,0,0,9,40,0,75,0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57],[0,0,5,10,10,128,0,156,0,0,18,165,0,0,33,61,0,0,0,1,9,144,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57,0,0,0,0,8,130,4,54,0,0,0,33,9,112,0,57],[0,0,0,5,9,144,2,114,0,0,4,59,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,184,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75,0,0,4,51,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,4,61,0,0,97,61,0,0,0,0,9,2,4,51,0,0,0,0,9,9,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,9,8,4,51,0,0,5,59,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159],[0,0,5,61,9,144,0,65,0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137],[0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140,0,0,0,0,6,0,32,25,0,0,0,33,7,32,0,57],[0,0,5,156,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,4,88,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,4,81,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,4,102,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,20,3,0,1,4,48],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,5,55,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,23,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,5,46,1,16,1,199,0,0,20,3,0,1,4,48,0,0,5,58,1,48,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54],[0,0,0,0,2,0,0,49,0,0,0,2,1,0,3,103,0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80],[0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,64,2,16],[0,0,5,11,8,0,0,65,0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25,0,0,5,59,4,96,1,151],[0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53,0,0,0,6,5,16,3,96,0,0,0,64,4,0,4,61],[0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140,0,0,8,32,0,0,65,61,0,0,0,128,6,80,2,112],[0,0,5,60,7,80,0,156,0,0,0,0,6,5,160,25,0,0,5,60,7,80,0,156,0,0,0,0,7,0,0,25],[0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,5,10,9,96,0,156,0,0,0,0,8,7,160,25],[0,0,0,64,7,96,2,112,0,0,5,10,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191],[0,0,5,2,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,5,2,6,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25],[0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57],[0,0,0,32,7,0,0,138,0,0,0,65,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,0,7,116,0,25],[0,0,0,0,8,71,0,75,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,5,10,9,112,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,8,128,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,112,4,63],[0,0,0,2,7,96,0,57,0,0,0,0,7,116,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114],[0,0,4,199,0,0,97,61,0,0,0,0,9,33,3,79,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,4,191,0,0,65,61,0,0,0,0,8,0,0,75],[0,0,4,201,0,0,97,61,0,0,0,0,8,4,4,51,0,0,0,0,8,8,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,8,7,4,51,0,0,5,59,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159],[0,0,5,61,8,128,0,65,0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137],[0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,33,6,64,0,57],[0,0,8,49,0,0,1,61,0,0,5,2,1,0,0,65,0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,33,1,16,1,199,0,0,0,9,2,0,0,41,20,1,19,242,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,5,2,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,4,242,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,4,234,0,0,65,61,0,0,0,0,7,5,0,75,0,0,5,1,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,6,42,0,0,97,61,0,0,0,31,2,64,0,57,0,0,0,96,5,32,1,143,0,0,0,128,2,80,1,191],[0,0,0,64,0,32,4,63,0,0,0,32,4,48,0,140,0,0,1,39,0,0,65,61,0,0,0,128,4,0,4,61],[0,0,0,8,4,64,0,108,0,0,3,118,0,0,129,61,0,0,0,160,4,80,0,57,0,0,5,34,6,0,0,65],[0,0,0,0,0,100,4,53,0,0,0,164,6,80,0,57,0,0,0,7,7,0,0,41,0,0,0,0,0,118,4,53],[0,0,0,196,6,80,0,57,0,0,0,0,0,6,4,53,0,0,0,68,6,0,0,57,0,1,0,0,0,6,0,29],[0,0,0,0,0,98,4,53,0,0,1,64,6,80,0,57,0,0,0,64,0,96,4,63,0,0,1,32,7,80,0,57],[0,0,5,35,6,0,0,65,0,3,0,0,0,7,0,29,0,0,0,0,0,103,4,53,0,0,1,0,6,80,1,191],[0,0,0,32,5,0,0,57,0,4,0,0,0,5,0,29,0,2,0,0,0,6,0,29,0,0,0,0,0,86,4,53],[0,0,0,0,5,2,4,51,0,0,0,0,2,0,4,20,0,0,0,9,6,0,0,41,0,0,0,4,6,96,0,140],[0,0,8,127,0,0,193,61,0,0,0,1,2,0,0,57,0,0,5,10,4,48,0,156,0,0,18,165,0,0,33,61],[0,0,8,147,0,0,1,61,0,0,5,58,1,48,0,156,0,0,18,165,0,0,33,61,0,0,0,64,1,48,0,57],[0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49],[0,0,0,2,1,0,3,103,0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,64,2,16,0,0,5,11,8,0,0,65],[0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25,0,0,5,59,4,96,1,151,0,0,0,0,4,132,1,159],[0,0,0,0,0,69,4,53,0,0,0,6,5,16,3,96,0,0,0,64,4,0,4,61,0,0,0,0,5,5,4,59],[0,0,0,128,6,80,0,140,0,0,8,225,0,0,65,61,0,0,0,128,6,80,2,112,0,0,5,60,7,80,0,156],[0,0,0,0,6,5,160,25,0,0,5,60,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57],[0,0,0,8,8,112,1,191,0,0,5,10,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112],[0,0,5,10,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,5,2,6,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,5,2,6,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112],[0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,32,7,0,0,138],[0,0,0,65,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,0,7,116,0,25,0,0,0,0,8,71,0,75],[0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,5,10,9,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,8,128,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57],[0,0,0,0,7,116,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,5,122,0,0,97,61],[0,0,0,0,9,33,3,79,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25],[0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57],[0,0,0,0,11,138,0,75,0,0,5,114,0,0,65,61,0,0,0,0,8,0,0,75,0,0,5,124,0,0,97,61],[0,0,0,0,8,4,4,51,0,0,0,0,8,8,0,75,0,0,12,17,0,0,97,61,0,0,0,0,8,7,4,51],[0,0,5,59,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,5,61,8,128,0,65],[0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207],[0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,33,6,64,0,57,0,0,8,242,0,0,1,61],[0,0,5,58,7,32,0,156,0,0,18,165,0,0,33,61,0,0,0,64,7,32,0,57,0,0,0,64,0,112,4,63],[0,0,0,1,7,0,0,58,0,0,0,0,7,114,4,54,0,0,0,0,8,80,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,12,17,0,0,97,61,0,0,0,248,9,96,2,16,0,0,5,11,10,0,0,65],[0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,5,59,6,128,1,151,0,0,0,0,6,166,1,159],[0,0,0,0,0,103,4,53,0,0,0,64,6,0,4,61,0,6,0,0,0,6,0,29,0,0,0,32,7,96,0,57],[0,0,0,0,6,1,4,51,0,0,0,0,8,6,0,75,0,0,5,171,0,0,97,61,0,0,0,0,8,0,0,25],[0,0,0,0,9,120,0,25,0,0,0,32,8,128,0,57,0,0,0,0,10,24,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,169,4,53,0,0,0,0,9,104,0,75,0,0,5,164,0,0,65,61,0,0,0,0,1,118,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,7,2,4,51,0,0,0,0,8,7,0,75,0,0,5,184,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,0,9,24,0,25,0,0,0,32,8,128,0,57,0,0,0,0,10,40,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,169,4,53,0,0,0,0,9,120,0,75,0,0,5,177,0,0,65,61],[0,0,0,0,1,23,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,103,0,25,0,0,0,6,6,0,0,41],[0,0,0,0,0,22,4,53,0,0,0,63,1,16,0,57,0,2,0,32,0,0,0,146,0,0,0,2,1,16,1,127],[0,0,0,0,2,97,0,25,0,0,0,0,1,18,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57],[0,5,0,0,0,2,0,29,0,0,5,10,2,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,1,16,1,144],[0,0,18,165,0,0,193,61,0,0,0,5,1,0,0,41,0,0,0,64,0,16,4,63,0,0,5,58,1,16,0,156],[0,0,18,165,0,0,33,61,0,0,0,10,7,0,0,41,0,0,0,68,1,112,0,57,0,0,0,0,1,19,3,79],[0,0,0,0,1,1,4,59,0,0,0,5,8,0,0,41,0,0,0,64,2,128,0,57,0,0,0,64,0,32,4,63],[0,0,0,32,2,128,0,57,0,0,5,62,6,0,0,65,0,0,0,0,0,98,4,53,0,0,0,21,2,0,0,57],[0,0,0,0,0,40,4,53,0,0,0,96,1,16,2,16,0,0,0,33,2,128,0,57,0,0,0,0,0,18,4,53],[0,0,1,36,1,112,0,57,0,0,0,0,2,19,3,79,0,0,0,64,6,0,4,61,0,4,0,0,0,6,0,29],[0,0,0,0,2,2,4,59,0,0,0,128,6,32,0,140,0,0,9,223,0,0,65,61,0,0,0,128,6,32,2,112],[0,0,5,60,7,32,0,156,0,0,0,0,6,2,160,25,0,0,5,60,7,32,0,156,0,0,0,0,7,0,0,25],[0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,5,10,9,96,0,156,0,0,0,0,8,7,160,25],[0,0,0,64,7,96,2,112,0,0,5,10,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191],[0,0,5,2,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,5,2,6,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25],[0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57],[0,0,0,65,7,96,0,57,0,0,0,2,7,112,1,127,0,0,0,4,7,112,0,41,0,0,0,4,8,112,0,108],[0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,5,10,9,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,8,128,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57],[0,0,0,4,8,0,0,41,0,0,0,0,7,120,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114],[0,0,6,22,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,167,0,25],[0,0,0,0,10,165,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57],[0,0,0,0,10,137,0,75,0,0,6,14,0,0,65,61,0,0,0,0,8,0,0,75,0,0,6,24,0,0,97,61],[0,0,0,4,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,0,8,8,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,8,7,4,51,0,0,5,59,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159],[0,0,5,61,8,128,0,65,0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137],[0,0,0,0,2,98,1,207,0,0,0,255,6,96,0,140,0,0,0,0,2,0,32,25,0,0,0,4,6,0,0,41],[0,0,0,33,6,96,0,57,0,0,9,241,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,6,55,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,6,47,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,6,70,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,5,2,1,0,0,65,0,0,5,2,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159],[0,0,20,3,0,1,4,48,0,0,5,2,1,16,1,151,0,0,0,0,1,19,3,79,0,0,0,0,3,84,0,73],[0,0,5,2,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,192,2,32,2,16,0,0,5,24,2,32,1,151],[0,0,5,26,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,20,1,19,252,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,1,5,2,0,48,1,157,0,0,5,2,5,48,1,151],[0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144,0,0,9,64,0,0,97,61,0,0,0,63,2,80,0,57],[0,0,5,54,2,32,1,151,0,0,0,64,6,0,4,61,0,0,0,0,2,38,0,25,0,0,0,0,3,98,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,5,10,4,32,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,0,4,86,4,54],[0,0,0,2,2,0,3,103,0,0,0,0,3,0,0,49,0,0,0,31,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,6,123,0,0,97,61,0,0,0,0,8,50,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,164,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,6,115,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,6,125,0,0,97,61,0,0,0,31,7,80,1,143,0,0,0,5,5,80,2,114,0,0,6,137,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,5,9,128,2,16,0,0,0,0,10,148,0,25,0,0,0,0,9,145,3,79],[0,0,0,0,9,9,4,59,0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,88,0,75],[0,0,6,129,0,0,65,61,0,0,0,0,8,7,0,75,0,0,6,152,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25,0,0,0,3,7,112,2,16,0,0,0,0,8,5,4,51],[0,0,0,0,8,120,1,207,0,0,0,0,8,120,2,47,0,0,0,0,1,1,4,59,0,0,1,0,7,112,0,137],[0,0,0,0,1,113,2,47,0,0,0,0,1,113,1,207,0,0,0,0,1,129,1,159,0,0,0,0,0,21,4,53],[0,0,0,0,1,6,4,51,0,0,0,32,1,16,0,140,0,0,9,216,0,0,193,61,0,0,0,10,6,0,0,41],[0,0,0,0,1,99,0,73,0,0,0,35,5,16,0,138,0,8,2,4,0,96,0,61,0,0,0,8,1,32,3,96],[0,0,0,0,1,1,4,59,0,0,5,11,6,0,0,65,0,0,0,0,7,81,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,5,11,5,80,1,151,0,0,5,11,8,16,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,1,39,0,0,193,61,0,0,0,0,4,4,4,51,0,5,0,0,0,4,0,29],[0,0,0,9,1,16,0,41,0,0,0,0,4,18,3,79,0,0,0,0,5,4,4,59,0,0,5,10,4,80,0,156],[0,0,1,39,0,0,33,61,0,0,0,5,4,80,2,16,0,0,0,0,3,67,0,73,0,0,0,32,6,16,0,57],[0,0,5,11,1,0,0,65,0,0,0,0,7,54,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,1,32,25],[0,0,5,11,3,48,1,151,0,0,5,11,8,96,1,151,0,0,0,0,9,56,0,75,0,0,0,0,1,0,128,25],[0,0,0,0,3,56,1,63,0,0,5,11,3,48,0,156,0,0,0,0,1,7,192,25,0,0,0,0,1,1,0,75],[0,0,1,39,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57,0,0,5,68,5,80,1,152],[0,0,6,211,0,0,97,61,0,0,0,0,2,98,3,79,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,115,0,25,0,0,0,0,7,114,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,6,203,0,0,65,61,0,0,0,0,2,0,0,75],[0,0,6,213,0,0,97,61,0,0,0,0,0,65,4,53,0,0,0,63,2,64,0,57,0,0,0,32,4,0,0,138],[0,0,0,0,2,66,1,111,0,0,0,0,2,33,0,25,0,0,0,0,4,18,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,64,57,0,0,5,10,5,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,32,4,63,0,0,5,2,2,0,0,65,0,0,5,2,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,64,3,48,2,16,0,0,0,0,1,1,4,51,0,0,5,2,4,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20],[0,0,5,2,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159],[0,0,5,13,1,16,1,199,0,0,128,16,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,39,0,0,97,61,0,0,0,0,2,0,0,49,0,0,0,10,3,32,0,106,0,0,0,35,5,48,0,138],[0,0,0,8,3,0,0,41,0,0,0,32,4,48,0,57,0,0,0,2,3,0,3,103,0,0,0,0,4,67,3,79],[0,0,0,0,4,4,4,59,0,0,5,11,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,5,11,5,80,1,151,0,0,5,11,8,64,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,1,1,4,59,0,8,0,0,0,1,0,29,0,0,0,0,1,6,0,75,0,0,1,39,0,0,193,61],[0,0,0,9,1,64,0,41,0,0,0,0,4,19,3,79,0,0,0,0,4,4,4,59,0,0,5,10,5,64,0,156],[0,0,1,39,0,0,33,61,0,0,0,0,5,66,0,73,0,0,0,32,1,16,0,57,0,0,5,11,6,0,0,65],[0,0,0,0,7,81,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,32,25,0,0,5,11,5,80,1,151],[0,0,5,11,8,16,1,151,0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63],[0,0,5,11,5,80,0,156,0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,1,39,0,0,193,61],[0,0,0,0,5,20,0,26,0,0,0,0,4,0,4,20,0,0,16,208,0,0,65,61,0,0,0,0,6,82,0,75],[0,0,16,208,0,0,65,61,0,0,5,2,6,64,0,156,0,0,2,154,0,0,33,61,0,0,5,2,1,16,1,151],[0,0,0,0,1,19,3,79,0,0,0,0,2,82,0,73,0,0,5,2,2,32,1,151,0,0,0,0,1,33,3,223],[0,0,0,192,2,64,2,16,0,0,5,24,2,32,1,151,0,0,5,26,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,16,2,0,0,57,20,1,19,252,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,5,2,0,48,1,157,0,0,5,2,3,48,1,151,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,17,218,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,54,2,32,1,151,0,0,0,64,5,0,4,61],[0,0,0,0,2,37,0,25,0,0,0,0,4,82,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,5,10,6,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,32,4,63,0,0,0,0,2,53,4,54,0,0,0,2,4,0,3,103,0,0,0,31,6,48,0,57],[0,0,0,5,6,96,2,114,0,0,7,84,0,0,97,61,0,0,0,0,7,64,3,104,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,146,0,25,0,0,0,0,9,151,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,104,0,75,0,0,7,76,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,7,86,0,0,97,61,0,0,0,31,6,48,1,143,0,0,0,5,3,48,2,114],[0,0,7,98,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,130,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,55,0,75,0,0,7,90,0,0,65,61,0,0,0,0,7,6,0,75,0,0,7,113,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,50,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,7,3,4,51,0,0,0,0,7,103,1,207,0,0,0,0,7,103,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,1,97,2,47,0,0,0,0,1,97,1,207,0,0,0,0,1,113,1,159],[0,0,0,0,0,19,4,53,0,0,0,0,1,5,4,51,0,0,0,32,1,16,0,140,0,0,9,216,0,0,193,61],[0,0,0,10,12,0,0,41,0,0,0,100,1,192,0,57,0,0,0,0,1,20,3,79,0,0,0,68,3,192,0,57],[0,0,0,0,5,52,3,79,0,0,0,36,3,192,0,57,0,0,0,0,6,52,3,79,0,0,1,36,3,192,0,57],[0,0,0,0,7,52,3,79,0,0,0,6,8,64,3,96,0,0,0,228,3,192,0,57,0,0,0,0,9,52,3,79],[0,0,0,196,3,192,0,57,0,0,0,0,10,52,3,79,0,0,0,164,3,192,0,57,0,0,0,0,11,52,3,79],[0,0,0,132,3,192,0,57,0,0,0,0,12,52,3,79,0,0,0,9,3,64,3,96,0,0,0,0,3,3,4,59],[0,0,0,0,4,6,4,59,0,0,0,0,5,5,4,59,0,0,0,0,6,1,4,59,0,0,0,0,12,12,4,59],[0,0,0,0,11,11,4,59,0,0,0,0,10,10,4,59,0,0,0,0,9,9,4,59,0,0,0,0,8,8,4,59],[0,0,0,0,7,7,4,59,0,0,0,0,2,2,4,51,0,0,0,64,1,0,4,61,0,0,1,192,13,16,0,57],[0,0,0,0,0,45,4,53,0,0,1,160,2,16,0,57,0,0,0,8,13,0,0,41,0,0,0,0,0,210,4,53],[0,0,1,128,2,16,0,57,0,0,0,5,13,0,0,41,0,0,0,0,0,210,4,53,0,0,1,96,2,16,0,57],[0,0,0,0,0,114,4,53,0,0,1,64,2,16,0,57,0,0,0,0,0,130,4,53,0,0,1,32,2,16,0,57],[0,0,0,0,0,146,4,53,0,0,1,0,2,16,0,57,0,0,0,0,0,162,4,53,0,0,0,224,2,16,0,57],[0,0,0,0,0,178,4,53,0,0,0,192,2,16,0,57,0,0,0,0,0,194,4,53,0,0,0,160,2,16,0,57],[0,0,0,0,0,98,4,53,0,0,0,128,2,16,0,57,0,0,0,0,0,82,4,53,0,0,0,96,2,16,0,57],[0,0,0,0,0,66,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,32,2,16,0,57],[0,0,5,70,3,0,0,65,0,0,0,0,0,50,4,53,0,0,1,192,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,5,71,3,16,0,156,0,0,18,165,0,0,33,61,0,0,1,224,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,5,2,4,0,0,65,0,0,5,2,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,5,2,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,13,1,16,1,199,0,0,128,16,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,39,0,0,97,61,0,0,0,0,1,1,4,59],[0,6,0,0,0,1,0,29,0,0,0,64,1,0,4,61,0,8,0,0,0,1,0,29,0,0,5,56,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,5,2,2,16,0,156,0,0,5,2,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,5,57,1,16,1,199,0,0,128,11,2,0,0,57,20,1,19,242,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,8,4,0,0,41,0,0,0,32,2,64,0,57],[0,0,0,0,1,1,4,59,0,0,5,72,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,128,3,64,0,57],[0,0,0,0,0,19,4,53,0,0,0,96,1,64,0,57,0,0,5,73,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,64,1,64,0,57,0,0,5,74,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,128,1,0,0,57],[0,0,0,0,0,20,4,53,0,0,5,75,1,64,0,156,0,0,18,165,0,0,33,61,0,0,0,8,4,0,0,41],[0,0,0,160,1,64,0,57,0,0,0,64,0,16,4,63,0,0,5,2,1,0,0,65,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,2,32,2,16,0,0,0,0,3,4,4,51,0,0,5,2,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20],[0,0,5,2,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159],[0,0,5,13,1,16,1,199,0,0,128,16,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,39,0,0,97,61,0,0,0,0,3,1,4,59,0,0,0,64,1,0,4,61,0,0,0,66,2,16,0,57],[0,0,0,6,4,0,0,41,0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57,0,0,5,76,4,0,0,65],[0,0,0,0,0,66,4,53,0,0,0,34,4,16,0,57,0,0,0,0,0,52,4,53,0,0,0,66,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,5,41,3,16,0,156,0,0,18,165,0,0,33,61,0,0,0,128,3,16,0,57],[0,0,0,64,0,48,4,63,0,0,5,2,3,0,0,65,0,0,5,2,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,5,2,4,16,0,156,0,0,0,0,1,3,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,5,2,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,16,175,0,0,1,61],[0,0,5,58,6,64,0,156,0,0,18,165,0,0,33,61,0,0,0,64,6,64,0,57,0,0,0,64,0,96,4,63],[0,0,0,0,7,33,3,79,0,0,0,1,6,0,0,58,0,0,0,0,6,100,4,54,0,0,0,0,7,112,3,80],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,12,17,0,0,97,61,0,0,0,248,8,80,2,16],[0,0,5,11,9,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,9,8,192,25,0,0,5,59,5,112,1,151],[0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53,0,0,0,64,5,0,4,61,0,0,0,6,6,0,0,41],[0,0,0,64,7,96,0,138,0,0,0,0,6,113,3,79,0,0,0,0,6,6,4,59,0,0,0,128,8,96,0,140],[0,0,9,122,0,0,65,61,0,0,0,128,8,96,2,112,0,0,5,60,9,96,0,156,0,0,0,0,8,6,160,25],[0,0,5,60,9,96,0,156,0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191],[0,0,5,10,11,128,0,156,0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,5,10,11,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191,0,0,5,2,8,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,32,10,144,2,112,0,0,5,2,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191],[0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25],[0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57],[0,0,0,0,9,154,1,111,0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,64,57,0,0,5,10,11,144,0,156,0,0,18,165,0,0,33,61,0,0,0,1,10,160,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,149,4,54],[0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114,0,0,8,109,0,0,97,61,0,0,0,0,11,33,3,79],[0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79],[0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75],[0,0,8,101,0,0,65,61,0,0,0,0,10,0,0,75,0,0,8,111,0,0,97,61,0,0,0,0,10,5,4,51],[0,0,0,0,10,10,0,75,0,0,12,17,0,0,97,61,0,0,0,0,10,9,4,51,0,0,5,59,10,160,1,151],[0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,5,61,10,160,0,65,0,0,0,0,0,169,4,53],[0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137,0,0,0,0,6,134,1,207,0,0,0,255,8,128,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,8,80,0,57,0,0,9,139,0,0,1,61,0,0,5,2,1,0,0,65],[0,0,5,2,3,80,0,156,0,0,0,0,5,1,128,25,0,0,0,96,3,80,2,16,0,0,0,64,4,64,2,16],[0,0,0,0,3,67,1,159,0,0,5,2,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,0,1,19,1,159,0,0,0,9,2,0,0,41,20,1,19,237,0,0,4,15,0,5,0,96,0,0,0,61],[0,0,0,1,2,32,1,143,0,3,0,0,0,1,3,85,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,1,5,2,0,48,1,157,0,0,5,2,3,48,1,152,0,0,8,191,0,0,97,61,0,0,0,63,4,48,0,57],[0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111,0,0,0,64,5,0,4,61,0,0,0,0,4,69,0,25],[0,5,0,0,0,5,0,29,0,0,0,0,5,84,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,5,10,6,64,0,156,0,0,18,165,0,0,33,61,0,0,0,1,5,80,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,31,4,48,1,143,0,0,0,5,5,0,0,41,0,0,0,0,8,53,4,54],[0,0,0,5,3,48,2,114,0,0,8,175,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,104,0,25,0,0,0,0,6,97,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,53,0,75,0,0,8,167,0,0,65,61,0,10,0,0,0,8,0,29],[0,0,0,0,5,4,0,75,0,0,8,191,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79],[0,0,0,10,3,48,0,41,0,0,0,3,4,64,2,16,0,0,0,0,5,3,4,51,0,0,0,0,5,69,1,207],[0,0,0,0,5,69,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,19,4,53,0,0,0,5,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,2,2,0,75,0,0,9,91,0,0,193,61,0,0,0,0,2,1,0,75],[0,0,8,217,0,0,193,61,0,0,0,64,4,0,4,61,0,10,0,0,0,4,0,29,0,0,5,16,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,4,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,2,1,0,0,41,0,0,0,0,3,1,4,51,0,9,0,0,0,3,0,29,0,0,0,36,1,64,0,57],[0,0,0,0,0,49,4,53,0,0,0,68,2,64,0,57,0,0,0,3,1,0,0,41,20,1,19,223,0,0,4,15],[0,0,0,9,1,0,0,41,0,0,0,31,1,16,0,57,0,0,0,32,2,0,0,138,0,0,0,0,1,33,1,111],[0,0,0,68,1,16,0,57,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,10,4,0,0,41,0,0,5,2,3,64,0,156,0,0,0,0,4,2,128,25,0,0,0,64,2,64,2,16],[0,0,2,84,0,0,1,61,0,0,5,58,6,64,0,156,0,0,18,165,0,0,33,61,0,0,0,64,6,64,0,57],[0,0,0,64,0,96,4,63,0,0,0,0,7,33,3,79,0,0,0,1,6,0,0,58,0,0,0,0,6,100,4,54],[0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,8,80,2,16,0,0,5,11,9,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,9,8,192,25],[0,0,5,59,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53,0,0,0,64,5,0,4,61],[0,0,0,6,6,0,0,41,0,0,0,96,6,96,0,138,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,128,8,112,0,140,0,0,10,55,0,0,65,61,0,0,0,128,8,112,2,112,0,0,5,60,9,112,0,156],[0,0,0,0,8,7,160,25,0,0,5,60,9,112,0,156,0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57],[0,0,0,8,10,144,1,191,0,0,5,10,11,128,0,156,0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112],[0,0,5,10,11,128,0,156,0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191,0,0,5,2,8,144,0,156],[0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112,0,0,5,2,8,144,0,156,0,0,0,0,10,9,160,25],[0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112],[0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138],[0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111,0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75],[0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57,0,0,5,10,11,144,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,10,160,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57],[0,0,0,0,9,149,4,54,0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114,0,0,9,46,0,0,97,61],[0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25],[0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57],[0,0,0,0,13,172,0,75,0,0,9,38,0,0,65,61,0,0,0,0,10,0,0,75,0,0,9,48,0,0,97,61],[0,0,0,0,10,5,4,51,0,0,0,0,10,10,0,75,0,0,12,17,0,0,97,61,0,0,0,0,10,9,4,51],[0,0,5,59,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,5,61,10,160,0,65],[0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137,0,0,0,0,7,135,1,207],[0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25,0,0,0,33,8,80,0,57,0,0,10,72,0,0,1,61],[0,0,0,31,3,80,1,143,0,0,0,5,2,80,2,114,0,0,9,75,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,5,6,64,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,0,1,4,64,0,57,0,0,0,0,6,36,0,75,0,0,9,68,0,0,65,61,0,0,0,0,4,3,0,75],[0,0,9,89,0,0,97,61,0,0,0,3,3,48,2,16,0,0,0,5,2,32,2,16,0,0,0,0,4,2,4,51],[0,0,0,0,4,52,1,207,0,0,0,0,4,52,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59],[0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207,0,0,0,0,1,65,1,159],[0,0,0,0,0,18,4,53,0,0,0,96,1,80,2,16,0,0,20,3,0,1,4,48,0,0,0,0,2,1,0,75],[0,0,10,248,0,0,193,61,0,0,5,36,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,9,1,0,0,41],[0,0,0,4,0,16,4,67,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,37,1,16,1,199,0,0,128,2,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,10,244,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,5,45,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,29,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,4,3,0,0,41,0,0,4,115,0,0,1,61,0,0,5,58,8,80,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,12,17,0,0,97,61,0,0,0,248,10,96,2,16,0,0,5,11,11,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,11,10,192,25,0,0,5,59,6,144,1,151,0,0,0,0,6,182,1,159,0,0,0,0,0,104,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,7,112,0,138,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,128,9,128,0,140,0,0,10,149,0,0,65,61,0,0,0,128,9,128,2,112,0,0,5,60,10,128,0,156],[0,0,0,0,9,8,160,25,0,0,5,60,10,128,0,156,0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57],[0,0,0,8,11,160,1,191,0,0,5,10,12,144,0,156,0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112],[0,0,5,10,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191,0,0,5,2,9,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,5,2,9,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112],[0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138],[0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,166,0,25,0,0,0,0,11,106,0,75],[0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,5,10,12,160,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,11,176,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57],[0,0,0,0,10,166,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114,0,0,9,198,0,0,97,61],[0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25],[0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57],[0,0,0,0,14,189,0,75,0,0,9,190,0,0,65,61,0,0,0,0,11,0,0,75,0,0,9,200,0,0,97,61],[0,0,0,0,11,6,4,51,0,0,0,0,11,11,0,75,0,0,12,17,0,0,97,61,0,0,0,0,11,10,4,51],[0,0,5,59,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159,0,0,5,61,11,176,0,65],[0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207],[0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,96,0,57,0,0,10,166,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,5,69,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,4,110,0,0,1,61,0,0,0,4,6,0,0,41],[0,0,5,58,6,96,0,156,0,0,18,165,0,0,33,61,0,0,0,4,7,0,0,41,0,0,0,64,6,112,0,57],[0,0,0,64,0,96,4,63,0,0,0,1,6,0,0,58,0,0,0,0,6,103,4,54,0,0,0,0,7,80,3,80],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,12,17,0,0,97,61,0,0,0,248,8,32,2,16],[0,0,5,11,9,0,0,65,0,0,0,0,2,2,0,75,0,0,0,0,9,8,192,25,0,0,5,59,2,112,1,151],[0,0,0,0,2,146,1,159,0,0,0,0,0,38,4,53,0,0,0,9,6,64,0,106,0,0,0,160,1,16,0,57],[0,0,0,0,2,19,3,79,0,0,0,0,2,2,4,59,0,0,0,31,6,96,0,138,0,0,5,11,7,96,1,151],[0,0,5,11,8,32,1,151,0,0,5,11,9,0,0,65,0,0,0,0,10,120,0,75,0,0,0,0,10,0,0,25],[0,0,0,0,10,9,64,25,0,0,0,0,7,120,1,63,0,0,0,0,8,98,0,75,0,0,0,0,9,0,64,25],[0,0,5,11,7,112,0,156,0,0,0,0,10,9,192,25,0,0,0,0,7,10,0,75,0,0,1,39,0,0,193,61],[0,0,0,9,8,32,0,41,0,0,0,0,7,131,3,79,0,0,0,0,7,7,4,59,0,0,5,10,9,112,0,156],[0,0,1,39,0,0,33,61,0,0,0,0,9,116,0,73,0,0,0,32,8,128,0,57,0,0,5,11,10,0,0,65],[0,0,0,0,11,152,0,75,0,0,0,0,11,0,0,25,0,0,0,0,11,10,32,25,0,0,5,11,9,144,1,151],[0,0,5,11,12,128,1,151,0,0,0,0,13,156,0,75,0,0,0,0,10,0,128,25,0,0,0,0,9,156,1,63],[0,0,5,11,9,144,0,156,0,0,0,0,10,11,192,25,0,0,0,0,9,10,0,75,0,0,1,39,0,0,193,61],[0,0,0,1,9,112,0,140,0,0,12,62,0,0,193,61,0,0,0,0,5,131,3,79,0,0,0,0,5,5,4,59],[0,0,0,1,7,0,0,138,0,0,5,11,8,0,0,65,0,0,0,0,7,117,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,8,32,25,0,0,5,11,5,80,1,151,0,0,5,11,9,80,0,156,0,0,0,0,8,0,128,25],[0,0,5,11,5,80,1,103,0,0,5,11,5,80,0,156,0,0,0,0,8,7,192,25,0,3,0,96,0,0,0,61],[0,0,0,0,5,8,0,75,0,0,13,164,0,0,193,61,0,0,0,64,5,0,4,61,0,3,0,0,0,5,0,29],[0,0,5,58,5,80,0,156,0,0,18,165,0,0,33,61,0,0,0,3,8,0,0,41,0,0,0,64,5,128,0,57],[0,0,0,64,0,80,4,63,0,0,0,32,5,128,0,57,0,0,5,61,7,0,0,65,0,0,0,0,0,117,4,53],[0,0,0,1,5,0,0,57,0,0,0,0,0,88,4,53,0,0,13,164,0,0,1,61,0,0,5,58,8,80,0,156],[0,0,18,165,0,0,33,61,0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79],[0,0,0,1,8,0,0,58,0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59],[0,0,0,0,0,152,4,53,0,0,12,17,0,0,97,61,0,0,0,248,10,112,2,16,0,0,5,11,11,0,0,65],[0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25,0,0,5,59,7,144,1,151,0,0,0,0,7,183,1,159],[0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61,0,0,0,64,6,96,0,138,0,0,0,0,8,97,3,79],[0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140,0,0,11,46,0,0,65,61,0,0,0,128,9,128,2,112],[0,0,5,60,10,128,0,156,0,0,0,0,9,8,160,25,0,0,5,60,10,128,0,156,0,0,0,0,10,0,0,25],[0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191,0,0,5,10,12,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,64,10,144,2,112,0,0,5,10,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191],[0,0,5,2,9,160,0,156,0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,5,2,9,160,0,156],[0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25],[0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57],[0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,167,0,25],[0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,5,10,12,160,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,11,176,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,160,4,63],[0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114],[0,0,10,131,0,0,97,61,0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16],[0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53],[0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75,0,0,10,123,0,0,65,61,0,0,0,0,11,0,0,75],[0,0,10,133,0,0,97,61,0,0,0,0,11,7,4,51,0,0,0,0,11,11,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,11,10,4,51,0,0,5,59,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159],[0,0,5,61,11,176,0,65,0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137],[0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,112,0,57],[0,0,11,63,0,0,1,61,0,0,5,58,9,96,0,156,0,0,18,165,0,0,33,61,0,0,0,64,9,96,0,57],[0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58,0,0,0,0,9,150,4,54],[0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,11,128,2,16,0,0,5,11,12,0,0,65,0,0,0,0,8,8,0,75,0,0,0,0,12,11,192,25],[0,0,5,59,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53,0,0,0,64,8,0,4,61],[0,8,0,64,0,112,0,146,0,0,0,8,9,16,3,96,0,0,0,0,9,9,4,59,0,0,0,128,10,144,0,140],[0,0,12,6,0,0,65,61,0,0,0,128,10,144,2,112,0,0,5,60,11,144,0,156,0,0,0,0,10,9,160,25],[0,0,5,60,11,144,0,156,0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191],[0,0,5,10,13,160,0,156,0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,5,10,13,160,0,156],[0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191,0,0,5,2,10,176,0,156,0,0,0,0,13,12,160,25],[0,0,0,32,12,176,2,112,0,0,5,2,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191],[0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25],[0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57],[0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25],[0,0,0,1,12,0,64,57,0,0,5,10,13,176,0,156,0,0,18,165,0,0,33,61,0,0,0,1,12,192,1,144],[0,0,18,165,0,0,193,61,0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54],[0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114,0,0,10,225,0,0,97,61,0,0,0,0,13,33,3,79],[0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16,0,0,0,0,7,251,0,25,0,0,0,0,15,253,3,79],[0,0,0,0,15,15,4,59,0,0,0,0,0,247,4,53,0,0,0,1,14,224,0,57,0,0,0,0,7,206,0,75],[0,0,10,217,0,0,65,61,0,0,0,0,7,0,0,75,0,0,10,227,0,0,97,61,0,0,0,0,7,8,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,11,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,12,160,2,16,0,0,0,0,7,124,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,123,4,53],[0,0,0,3,7,160,2,16,0,0,0,248,7,112,0,137,0,0,0,0,9,121,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,9,0,32,25,0,0,0,33,7,128,0,57,0,0,0,0,0,151,4,53,0,0,13,48,0,0,1,61],[0,0,0,5,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,11,27,0,0,97,61],[0,0,5,11,2,0,0,65,0,0,0,32,3,16,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,0,5,11,1,16,1,151,0,0,0,0,4,1,0,75,0,0,0,0,2,0,160,25,0,0,5,11,1,16,0,156],[0,0,0,0,2,3,192,25,0,0,0,0,1,2,0,75,0,0,1,39,0,0,193,61,0,0,0,10,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57],[0,0,0,0,2,33,0,75,0,0,1,39,0,0,193,61,0,0,0,0,1,1,0,75,0,0,11,27,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,5,43,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,5,44,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,42,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,4,3,0,0,41,0,0,1,10,0,0,1,61,0,0,0,64,3,0,4,61],[0,0,0,36,1,48,0,57,0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53,0,0,5,32,1,0,0,65],[0,0,0,0,0,19,4,53,0,10,0,0,0,3,0,29,0,0,0,4,1,48,0,57,0,0,0,6,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,0,0,1,0,4,20,0,0,0,9,2,0,0,41,0,0,0,4,2,32,0,140],[0,0,11,159,0,0,193,61,0,0,0,1,3,0,0,49,0,0,0,32,1,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,11,209,0,0,1,61,0,0,5,58,9,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58],[0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,12,17,0,0,97,61,0,0,0,248,11,128,2,16,0,0,5,11,12,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,12,11,192,25,0,0,5,59,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53],[0,0,0,64,9,0,4,61,0,0,5,58,8,144,0,156,0,0,18,165,0,0,33,61,0,0,0,32,8,96,0,138],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63],[0,0,0,32,10,144,0,57,0,0,5,62,11,0,0,65,0,0,0,0,0,186,4,53,0,0,0,21,10,0,0,57],[0,0,0,0,0,169,4,53,0,0,0,96,8,128,2,16,0,0,0,33,10,144,0,57,0,0,0,0,0,138,4,53],[0,0,0,192,6,96,0,57,0,0,0,0,6,97,3,79,0,0,0,64,8,0,4,61,0,0,0,0,6,6,4,59],[0,8,0,0,0,6,0,29,0,0,0,128,10,96,0,140,0,0,12,105,0,0,65,61,0,0,0,8,6,0,0,41],[0,0,0,128,10,96,2,112,0,0,5,60,11,96,0,156,0,0,0,0,10,6,160,25,0,0,5,60,11,96,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,5,10,13,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,5,10,13,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,13,192,1,191,0,0,5,2,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112],[0,0,5,2,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140],[0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140],[0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111],[0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57],[0,0,5,10,13,176,0,156,0,0,18,165,0,0,33,61,0,0,0,1,12,192,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57],[0,0,0,5,12,192,2,114,0,0,11,140,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25],[0,0,0,5,15,224,2,16,0,0,0,0,6,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59],[0,0,0,0,0,246,4,53,0,0,0,1,14,224,0,57,0,0,0,0,6,206,0,75,0,0,11,132,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,11,142,0,0,97,61,0,0,0,0,6,8,4,51,0,0,0,0,6,6,0,75],[0,0,12,17,0,0,97,61,0,0,0,0,6,11,4,51,0,0,5,59,6,96,1,151,0,0,0,248,12,160,2,16],[0,0,0,0,6,108,1,159,0,0,5,61,6,96,0,65,0,0,0,0,0,107,4,53,0,0,0,3,6,160,2,16],[0,0,0,248,6,96,0,137,0,0,0,8,10,96,1,239,0,0,0,255,6,96,0,140,0,0,0,0,10,0,32,25],[0,0,0,33,6,128,0,57,0,0,0,0,0,166,4,53,0,0,12,124,0,0,1,61,0,0,5,2,2,0,0,65],[0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,10,4,0,0,41,0,0,5,2,3,64,0,156],[0,0,0,0,2,4,64,25,0,0,0,64,2,32,2,16,0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,5,38,1,16,1,199,0,0,0,9,2,0,0,41,20,1,19,242,0,0,4,15,0,0,0,10,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,5,2,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,11,190,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,11,182,0,0,65,61,0,0,0,0,7,5,0,75,0,0,11,205,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,10,6,96,0,41,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,1,0,0,0,3,0,31,0,3,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,12,21,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,10,1,32,0,41],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,5,10,4,16,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,2,48,0,140,0,0,1,39,0,0,65,61,0,0,0,68,4,16,0,57,0,0,0,36,5,16,0,57],[0,0,0,10,2,0,0,41,0,0,0,0,2,2,4,51,0,0,0,0,2,2,0,75,0,0,12,50,0,0,193,61],[0,0,0,32,2,16,0,57,0,0,5,34,6,0,0,65,0,0,0,0,0,98,4,53,0,0,0,7,6,0,0,41],[0,0,0,0,0,101,4,53,0,0,0,8,5,0,0,41,0,0,0,0,0,84,4,53,0,0,0,1,4,0,0,41],[0,0,0,0,0,65,4,53,0,0,5,41,4,16,0,156,0,0,18,165,0,0,33,61,0,0,0,128,4,16,0,57],[0,10,0,0,0,4,0,29,0,0,0,64,0,64,4,63,0,0,5,42,4,16,0,156,0,0,18,165,0,0,33,61],[0,0,0,192,4,16,0,57,0,0,0,64,0,64,4,63,0,0,0,4,4,0,0,41,0,0,0,10,5,0,0,41],[0,0,0,0,0,69,4,53,0,0,0,160,5,16,0,57,0,0,5,35,4,0,0,65,0,7,0,0,0,5,0,29],[0,0,0,0,0,69,4,53,0,0,0,0,4,1,4,51,0,0,0,0,1,0,4,20,0,0,0,9,5,0,0,41],[0,0,0,4,5,80,0,140,0,0,15,43,0,0,193,61,0,0,0,1,2,0,0,57,0,0,5,10,1,48,0,156],[0,0,18,165,0,0,33,61,0,0,15,65,0,0,1,61,0,0,5,58,7,128,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,7,128,0,57,0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,10,0,0,58],[0,0,0,0,10,168,4,54,0,0,0,0,7,112,3,80,0,0,0,0,11,7,4,59,0,0,0,0,0,186,4,53],[0,0,13,41,0,0,193,61,0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57],[0,0,0,65,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,12,34,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,12,26,0,0,65,61,0,0,0,0,6,4,0,75,0,0,12,49,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,6,70,0,0,1,61,0,0,5,16,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,4,3,0,0,41,0,0,0,0,0,50,4,53,0,0,0,54,2,0,0,57],[0,0,0,0,0,37,4,53,0,0,5,39,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,100,2,16,0,57],[0,0,5,40,3,0,0,65,0,0,1,10,0,0,1,61,0,0,0,64,8,0,4,61,0,3,0,0,0,8,0,29],[0,0,0,56,8,112,0,140,0,0,13,147,0,0,65,61,0,0,0,32,9,112,2,112,0,0,5,2,8,112,0,156],[0,0,0,0,9,7,160,25,0,0,5,2,8,112,0,156,0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57],[0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112],[0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57],[0,0,0,3,10,0,0,41,0,0,5,58,10,160,0,156,0,0,18,165,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,3,10,0,0,41,0,0,0,64,9,160,0,57,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,58],[0,0,0,0,9,154,4,54,0,0,0,0,5,80,3,80,0,0,0,0,5,5,4,59,0,0,0,0,0,89,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,5,80,1,151,0,0,0,248,10,128,2,16,0,0,0,0,5,90,1,159],[0,0,5,63,5,80,1,199,0,0,0,0,0,89,4,53,0,0,0,3,5,128,2,16,0,0,0,248,5,80,1,95],[0,0,0,0,5,87,1,207,0,0,0,3,7,0,0,41,0,0,0,33,7,112,0,57,0,0,0,0,0,87,4,53],[0,0,13,164,0,0,1,61,0,0,5,58,6,128,0,156,0,0,18,165,0,0,33,61,0,0,0,64,6,128,0,57],[0,0,0,64,0,96,4,63,0,0,0,0,6,33,3,79,0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54],[0,0,0,0,6,96,3,80,0,0,0,0,11,6,4,59,0,0,0,0,0,186,4,53,0,0,12,17,0,0,97,61],[0,0,0,8,13,0,0,41,0,0,0,248,6,208,2,16,0,0,5,11,12,0,0,65,0,0,0,0,13,13,0,75],[0,0,0,0,12,6,192,25,0,0,5,59,6,176,1,151,0,0,0,0,6,198,1,159,0,0,0,0,0,106,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,11,96,0,57,0,0,0,0,10,3,4,51,0,0,0,0,12,10,0,75],[0,0,12,137,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57],[0,0,0,0,14,60,0,25,0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,172,0,75],[0,0,12,130,0,0,65,61,0,0,0,0,3,186,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,106,0,25],[0,0,0,32,11,48,0,57,0,0,0,0,10,4,4,51,0,0,0,0,12,10,0,75,0,0,12,152,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,76,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,172,0,75,0,0,12,145,0,0,65,61],[0,0,0,0,4,186,0,25,0,0,0,0,0,4,4,53,0,0,0,0,3,58,0,25,0,0,0,32,10,48,0,57],[0,0,0,0,4,5,4,51,0,0,0,0,11,4,0,75,0,0,12,167,0,0,97,61,0,0,0,0,11,0,0,25],[0,0,0,0,12,171,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,91,0,25,0,0,0,0,13,13,4,51],[0,0,0,0,0,220,4,53,0,0,0,0,12,75,0,75,0,0,12,160,0,0,65,61,0,0,0,0,5,164,0,25],[0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,7,4,51],[0,0,0,0,10,4,0,75,0,0,12,182,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,0,11,90,0,25],[0,0,0,32,10,160,0,57,0,0,0,0,12,122,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53],[0,0,0,0,11,74,0,75,0,0,12,175,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53],[0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,9,4,51,0,0,0,0,7,4,0,75],[0,0,12,197,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,10,87,0,25,0,0,0,32,7,112,0,57],[0,0,0,0,11,151,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,71,0,75],[0,0,12,190,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25],[0,0,0,32,5,48,0,57,0,0,0,0,4,8,4,51,0,0,0,0,7,4,0,75,0,0,12,212,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,0,9,87,0,25,0,0,0,32,7,112,0,57,0,0,0,0,10,135,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,169,4,53,0,0,0,0,9,71,0,75,0,0,12,205,0,0,65,61],[0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,99,0,73,0,0,0,0,3,52,0,25],[0,0,0,0,0,54,4,53,0,0,0,63,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111],[0,0,0,0,7,100,0,25,0,0,0,0,4,71,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,5,10,5,112,0,156,0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,112,4,63,0,0,0,10,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,5,82,0,73,0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,5,11,8,0,0,65],[0,0,0,0,9,84,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,5,11,5,80,1,151],[0,0,5,11,10,64,1,151,0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63],[0,0,5,11,5,80,0,156,0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,1,39,0,0,193,61],[0,0,0,9,5,64,0,41,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59,0,0,5,10,8,64,0,156],[0,0,1,39,0,0,33,61,0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57,0,0,5,11,9,0,0,65],[0,0,0,0,10,133,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25,0,0,5,11,8,128,1,151],[0,0,5,11,11,80,1,151,0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25,0,0,0,0,8,139,1,63],[0,0,5,11,8,128,0,156,0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75,0,0,1,39,0,0,193,61],[0,0,0,1,8,64,0,140,0,0,17,245,0,0,193,61,0,0,0,0,8,81,3,79,0,0,0,0,8,8,4,59],[0,0,0,1,9,0,0,138,0,0,5,11,10,0,0,65,0,0,0,0,9,152,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,10,32,25,0,0,5,11,8,128,1,151,0,0,5,11,11,128,0,156,0,0,0,0,10,0,128,25],[0,0,5,11,8,128,1,103,0,0,5,11,8,128,0,156,0,0,0,0,10,9,192,25,0,0,0,96,8,0,0,57],[0,0,0,0,9,10,0,75,0,0,18,86,0,0,193,61,0,0,5,58,8,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57,0,0,5,61,9,0,0,65],[0,0,0,0,0,152,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53,0,0,0,0,8,7,0,25],[0,0,18,86,0,0,1,61,0,0,0,248,7,144,2,16,0,0,5,11,12,0,0,65,0,0,0,0,9,9,0,75],[0,0,0,0,12,7,192,25,0,0,5,59,7,176,1,151,0,0,0,0,7,199,1,159,0,0,0,0,0,122,4,53],[0,0,0,64,10,0,4,61,0,0,5,58,7,160,0,156,0,0,18,165,0,0,33,61,0,0,0,8,12,0,0,41],[0,0,0,32,7,192,0,138,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,64,9,160,0,57],[0,0,0,64,0,144,4,63,0,0,0,32,9,160,0,57,0,0,5,62,11,0,0,65,0,0,0,0,0,185,4,53],[0,0,0,21,9,0,0,57,0,0,0,0,0,154,4,53,0,0,0,96,7,112,2,16,0,0,0,33,9,160,0,57],[0,0,0,0,0,121,4,53,0,0,0,192,7,192,0,57,0,0,0,0,7,113,3,79,0,0,0,64,9,0,4,61],[0,0,0,0,7,7,4,59,0,8,0,0,0,7,0,29,0,0,0,128,11,112,0,140,0,0,14,5,0,0,65,61],[0,0,0,8,7,0,0,41,0,0,0,128,11,112,2,112,0,0,5,60,12,112,0,156,0,0,0,0,11,7,160,25],[0,0,5,60,12,112,0,156,0,0,0,0,12,0,0,25,0,0,0,16,12,0,32,57,0,0,0,8,13,192,1,191],[0,0,5,10,14,176,0,156,0,0,0,0,13,12,160,25,0,0,0,64,12,176,2,112,0,0,5,10,14,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,4,14,208,1,191,0,0,5,2,11,192,0,156,0,0,0,0,14,13,160,25],[0,0,0,32,13,192,2,112,0,0,5,2,11,192,0,156,0,0,0,0,13,12,160,25,0,0,0,2,7,224,1,191],[0,0,255,255,12,208,0,140,0,0,0,0,7,14,160,25,0,0,0,16,12,208,2,112,0,0,0,0,12,13,160,25],[0,0,0,255,12,192,0,140,0,0,0,1,7,112,32,57,0,0,0,32,12,0,0,138,0,6,0,0,0,7,0,29],[0,0,0,65,13,112,0,57,0,0,0,0,12,205,1,111,0,0,0,0,12,201,0,25,0,0,0,0,13,156,0,75],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,64,57,0,0,5,10,14,192,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,13,208,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,192,4,63,0,0,0,6,7,0,0,41],[0,0,0,2,12,112,0,57,0,0,0,0,12,201,4,54,0,0,0,33,13,112,0,57,0,0,0,5,13,208,2,114],[0,0,13,127,0,0,97,61,0,0,0,0,14,33,3,79,0,0,0,0,15,0,0,25,0,0,0,5,7,240,2,16],[0,0,0,0,11,124,0,25,0,0,0,0,7,126,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,123,4,53],[0,0,0,1,15,240,0,57,0,0,0,0,7,223,0,75,0,0,13,119,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,13,129,0,0,97,61,0,0,0,0,7,9,4,51,0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61],[0,0,0,0,7,12,4,51,0,0,5,59,7,112,1,151,0,0,0,6,13,0,0,41,0,0,0,248,11,208,2,16],[0,0,0,0,7,123,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,124,4,53,0,0,0,3,7,208,2,16],[0,0,0,248,7,112,0,137,0,0,0,8,11,112,1,239,0,0,0,255,7,112,0,140,0,0,0,0,11,0,32,25],[0,0,0,33,7,144,0,57,0,0,0,0,0,183,4,53,0,0,14,24,0,0,1,61,0,0,0,3,8,0,0,41],[0,0,5,58,8,128,0,156,0,0,18,165,0,0,33,61,0,0,0,3,9,0,0,41,0,0,0,64,8,144,0,57],[0,0,0,64,0,128,4,63,0,0,0,1,8,0,0,58,0,0,0,0,8,137,4,54,0,0,0,0,5,80,3,80],[0,0,0,0,5,5,4,59,0,0,0,0,0,88,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,112,2,16],[0,0,5,59,5,80,1,151,0,0,0,0,5,117,1,159,0,0,5,11,5,80,1,103,0,0,0,0,0,88,4,53],[0,0,0,128,1,16,0,138,0,0,0,0,5,19,3,79,0,0,0,96,1,0,0,57,0,0,0,0,5,5,4,59],[0,0,0,0,5,5,0,75,0,0,14,212,0,0,193,61,0,0,5,11,5,0,0,65,0,0,0,0,7,98,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,5,128,25,0,0,5,11,6,96,1,151,0,0,5,11,8,32,1,151],[0,0,0,0,9,104,0,75,0,0,0,0,5,0,128,25,0,0,0,0,6,104,1,63,0,0,5,11,6,96,0,156],[0,0,0,0,5,7,192,25,0,0,0,0,5,5,0,75,0,0,1,39,0,0,193,61,0,0,0,8,5,0,0,41],[0,0,0,0,6,5,4,51,0,0,0,6,5,0,0,41,0,0,0,0,7,5,4,51,0,0,0,5,5,0,0,41],[0,0,0,0,8,5,4,51,0,0,0,4,5,0,0,41,0,0,0,0,9,5,4,51,0,0,0,3,5,0,0,41],[0,0,0,0,10,5,4,51,0,0,0,9,5,32,0,41,0,0,0,0,2,83,3,79,0,0,0,0,2,2,4,59],[0,0,5,10,11,32,0,156,0,0,1,39,0,0,33,61,0,0,0,0,11,36,0,73,0,0,0,32,5,80,0,57],[0,0,5,11,12,0,0,65,0,0,0,0,13,181,0,75,0,0,0,0,13,0,0,25,0,0,0,0,13,12,32,25],[0,0,5,11,11,176,1,151,0,0,5,11,14,80,1,151,0,0,0,0,15,190,0,75,0,0,0,0,12,0,128,25],[0,0,0,0,11,190,1,63,0,0,5,11,11,176,0,156,0,0,0,0,12,13,192,25,0,0,0,0,11,12,0,75],[0,0,1,39,0,0,193,61,0,0,0,0,6,103,0,25,0,0,0,0,6,134,0,25,0,0,0,0,6,150,0,25],[0,0,0,0,6,166,0,25,0,0,0,0,6,38,0,25,0,0,0,0,7,1,4,51,0,0,0,0,6,118,0,25],[0,0,0,64,7,0,4,61,0,0,5,10,6,96,1,151,0,0,0,56,8,96,0,140,0,0,15,246,0,0,65,61],[0,0,0,32,9,96,2,112,0,0,5,2,8,96,0,156,0,0,0,0,9,6,160,25,0,0,5,2,8,96,0,156],[0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140],[0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57,0,0,5,58,10,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,0,8,152,1,159,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,9,67,3,79],[0,0,0,2,4,128,0,58,0,0,0,0,4,71,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59],[0,0,0,0,0,148,4,53,0,0,12,17,0,0,97,61,0,0,5,59,9,144,1,151,0,0,0,248,10,128,2,16],[0,0,0,0,9,154,1,159,0,0,5,65,9,144,1,199,0,0,0,0,0,148,4,53,0,0,0,3,4,128,2,16],[0,0,0,248,4,64,1,95,0,0,0,0,4,70,1,207,0,0,0,33,6,112,0,57,0,0,0,0,0,70,4,53],[0,0,16,6,0,0,1,61,0,0,5,58,7,144,0,156,0,0,18,165,0,0,33,61,0,0,0,64,7,144,0,57],[0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,11,0,0,58,0,0,0,0,11,185,4,54],[0,0,0,0,7,112,3,80,0,0,0,0,12,7,4,59,0,0,0,0,0,203,4,53,0,0,12,17,0,0,97,61],[0,0,0,8,14,0,0,41,0,0,0,248,7,224,2,16,0,0,5,11,13,0,0,65,0,0,0,0,14,14,0,75],[0,0,0,0,13,7,192,25,0,0,5,59,7,192,1,151,0,0,0,0,7,215,1,159,0,0,0,0,0,123,4,53],[0,0,0,64,7,0,4,61,0,0,0,32,12,112,0,57,0,0,0,0,11,3,4,51,0,0,0,0,13,11,0,75],[0,0,14,37,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57],[0,0,0,0,15,61,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75],[0,0,14,30,0,0,65,61,0,0,0,0,3,203,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,123,0,25],[0,0,0,32,12,48,0,57,0,0,0,0,11,4,4,51,0,0,0,0,13,11,0,75,0,0,14,52,0,0,97,61],[0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,77,0,25],[0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75,0,0,14,45,0,0,65,61],[0,0,0,0,4,203,0,25,0,0,0,0,0,4,4,53,0,0,0,0,3,59,0,25,0,0,0,32,11,48,0,57],[0,0,0,0,4,5,4,51,0,0,0,0,12,4,0,75,0,0,14,67,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,92,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,76,0,75,0,0,14,60,0,0,65,61,0,0,0,0,5,180,0,25],[0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,6,4,51],[0,0,0,0,11,4,0,75,0,0,14,82,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,91,0,25],[0,0,0,32,11,176,0,57,0,0,0,0,13,107,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53],[0,0,0,0,12,75,0,75,0,0,14,75,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53],[0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57,0,0,0,0,4,8,4,51,0,0,0,0,6,4,0,75],[0,0,14,97,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,11,86,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,12,134,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53,0,0,0,0,11,70,0,75],[0,0,14,90,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25],[0,0,0,32,5,48,0,57,0,0,0,0,4,10,4,51,0,0,0,0,6,4,0,75,0,0,14,112,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,0,8,86,0,25,0,0,0,32,6,96,0,57,0,0,0,0,11,166,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,184,4,53,0,0,0,0,8,70,0,75,0,0,14,105,0,0,65,61],[0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,3,52,0,25,0,0,0,32,5,48,0,57],[0,0,0,0,4,9,4,51,0,0,0,0,6,4,0,75,0,0,14,127,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,8,86,0,25,0,0,0,32,6,96,0,57,0,0,0,0,10,150,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,168,4,53,0,0,0,0,8,70,0,75,0,0,14,120,0,0,65,61,0,0,0,0,5,84,0,25],[0,0,0,0,0,5,4,53,0,0,0,0,3,115,0,73,0,0,0,0,3,52,0,25,0,0,0,0,0,55,4,53],[0,0,0,63,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111,0,0,0,0,6,116,0,25],[0,0,0,0,4,70,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,5,96,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,96,4,63],[0,0,0,10,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79,0,0,0,0,5,82,0,73],[0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,5,11,8,0,0,65,0,0,0,0,9,84,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,5,11,5,80,1,151,0,0,5,11,10,64,1,151],[0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63,0,0,5,11,5,80,0,156],[0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,1,39,0,0,193,61,0,0,0,9,5,64,0,41],[0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59,0,0,5,10,8,64,0,156,0,0,1,39,0,0,33,61],[0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57,0,0,5,11,9,0,0,65,0,0,0,0,10,133,0,75],[0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25,0,0,5,11,8,128,1,151,0,0,5,11,11,80,1,151],[0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25,0,0,0,0,8,139,1,63,0,0,5,11,8,128,0,156],[0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75,0,0,1,39,0,0,193,61,0,0,0,1,8,64,0,140],[0,0,18,29,0,0,193,61,0,0,0,0,8,81,3,79,0,0,0,0,8,8,4,59,0,0,0,1,9,0,0,138],[0,0,5,11,10,0,0,65,0,0,0,0,9,152,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,10,32,25],[0,0,5,11,8,128,1,151,0,0,5,11,11,128,0,156,0,0,0,0,10,0,128,25,0,0,5,11,8,128,1,103],[0,0,5,11,8,128,0,156,0,0,0,0,10,9,192,25,0,0,0,96,8,0,0,57,0,0,0,0,9,10,0,75],[0,0,18,162,0,0,193,61,0,0,5,58,8,96,0,156,0,0,18,165,0,0,33,61,0,0,0,64,8,96,0,57],[0,0,0,64,0,128,4,63,0,0,0,32,8,96,0,57,0,0,5,61,9,0,0,65,0,0,0,0,0,152,4,53],[0,0,0,1,8,0,0,57,0,0,0,0,0,134,4,53,0,0,0,0,8,6,0,25,0,0,18,162,0,0,1,61],[0,0,5,56,1,0,0,65,0,0,0,0,0,16,4,57,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,57,1,16,1,199],[0,0,128,11,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,0,0,1,1,4,59,0,0,0,128,3,16,0,140,0,0,15,141,0,0,65,61],[0,0,0,128,3,16,2,112,0,0,5,60,4,16,0,156,0,0,0,0,3,1,160,25,0,0,5,60,4,16,0,156],[0,0,0,0,4,0,0,25,0,0,0,16,4,0,32,57,0,0,0,8,5,64,1,191,0,0,5,10,6,48,0,156],[0,0,0,0,5,4,160,25,0,0,0,64,4,48,2,112,0,0,5,10,6,48,0,156,0,0,0,0,4,3,160,25],[0,0,0,4,3,80,1,191,0,0,5,2,6,64,0,156,0,0,0,0,3,5,160,25,0,0,0,32,6,64,2,112],[0,0,5,2,5,64,0,156,0,0,0,0,6,4,160,25,0,0,0,2,5,48,1,191,0,0,255,255,4,96,0,140],[0,0,0,0,5,3,160,25,0,0,0,16,3,96,2,112,0,0,0,0,3,6,160,25,0,0,0,255,3,48,0,140],[0,0,0,1,5,80,32,57,0,0,0,65,3,80,0,57,0,0,0,2,3,48,1,127,0,0,0,0,3,50,0,25],[0,0,0,0,4,35,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,6,48,0,156],[0,0,18,165,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,48,4,63],[0,0,0,2,3,80,0,57,0,0,0,0,6,50,4,54,0,0,0,2,3,0,3,103,0,0,0,0,4,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,15,25,0,0,97,61,0,0,0,0,8,67,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,15,17,0,0,65,61,0,0,0,0,7,0,0,75,0,0,15,27,0,0,97,61,0,0,0,0,7,2,4,51],[0,0,0,0,7,7,0,75,0,0,12,17,0,0,97,61,0,0,0,0,7,6,4,51,0,0,5,59,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,5,61,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,1,81,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,1,0,32,25,0,0,0,33,5,32,0,57,0,0,15,160,0,0,1,61,0,0,5,2,3,0,0,65],[0,0,5,2,5,32,0,156,0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16,0,0,5,2,5,64,0,156],[0,0,0,0,4,3,128,25,0,0,0,96,4,64,2,16,0,0,0,0,2,36,1,159,0,0,5,2,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,0,1,18,1,159,0,0,0,9,2,0,0,41],[20,1,19,237,0,0,4,15,0,8,0,96,0,0,0,61,0,6,0,128,0,0,0,61,0,0,0,1,2,32,1,143],[0,3,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,1,5,2,0,16,1,157,0,0,5,2,3,16,1,152],[0,0,15,110,0,0,97,61,0,0,0,63,1,48,0,57,0,0,0,32,4,0,0,138,0,0,0,0,1,65,1,111],[0,0,0,64,4,0,4,61,0,0,0,0,1,20,0,25,0,8,0,0,0,4,0,29,0,0,0,0,4,65,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,10,5,16,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,31,1,48,1,143],[0,0,0,8,4,0,0,41,0,0,0,0,8,52,4,54,0,0,0,3,4,0,3,103,0,0,0,5,3,48,2,114],[0,0,15,94,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25],[0,0,0,0,6,100,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,53,0,75,0,0,15,86,0,0,65,61,0,6,0,0,0,8,0,29,0,0,0,0,5,1,0,75],[0,0,15,110,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,4,52,3,79,0,0,0,6,3,48,0,41],[0,0,0,3,1,16,2,16,0,0,0,0,5,3,4,51,0,0,0,0,5,21,1,207,0,0,0,0,5,21,2,47],[0,0,0,0,4,4,4,59,0,0,1,0,1,16,0,137,0,0,0,0,4,20,2,47,0,0,0,0,1,20,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,19,4,53,0,0,0,8,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,0,0,2,2,0,75,0,0,15,197,0,0,193,61,0,0,0,0,2,1,0,75,0,0,15,241,0,0,193,61],[0,0,0,64,4,0,4,61,0,9,0,0,0,4,0,29,0,0,5,16,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,0,4,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,10,1,0,0,41],[0,0,0,0,3,1,4,51,0,10,0,0,0,3,0,29,0,0,0,36,1,64,0,57,0,0,0,0,0,49,4,53],[0,0,0,68,2,64,0,57,0,0,0,7,1,0,0,41,20,1,19,223,0,0,4,15,0,0,0,10,1,0,0,41],[0,0,0,31,1,16,0,57,0,0,0,32,2,0,0,138,0,0,0,0,1,33,1,111,0,0,0,68,1,16,0,57],[0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,9,4,0,0,41],[0,0,8,221,0,0,1,61,0,0,5,58,3,32,0,156,0,0,18,165,0,0,33,61,0,0,0,64,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,1,3,0,0,58,0,0,0,0,5,50,4,54,0,0,0,0,4,0,0,49],[0,0,0,2,3,0,3,103,0,0,0,0,6,67,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,12,17,0,0,97,61,0,0,0,248,7,16,2,16,0,0,5,11,8,0,0,65],[0,0,0,0,1,1,0,75,0,0,0,0,8,7,192,25,0,0,5,59,1,96,1,151,0,0,0,0,1,129,1,159],[0,0,0,0,0,21,4,53,0,0,0,64,1,0,4,61,0,0,0,32,6,16,0,57,0,0,0,0,5,2,4,51],[0,0,0,0,7,5,0,75,0,0,15,174,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,103,0,25],[0,0,0,32,7,112,0,57,0,0,0,0,9,39,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53],[0,0,0,0,8,87,0,75,0,0,15,167,0,0,65,61,0,0,0,0,2,101,0,25,0,0,5,77,6,0,0,65],[0,0,0,0,0,98,4,53,0,0,0,2,2,80,0,57,0,0,0,0,0,33,4,53,0,0,0,65,2,80,0,57],[0,0,0,2,5,32,1,127,0,0,0,0,2,21,0,25,0,0,0,0,5,82,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,5,10,6,32,0,156,0,0,18,165,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,18,165,0,0,193,61,0,0,0,10,6,0,0,41,0,0,1,196,5,96,0,57,0,0,0,64,0,32,4,63],[0,0,0,0,2,83,3,79,0,0,0,0,5,100,0,73,0,0,0,35,6,80,0,138,0,0,0,0,2,2,4,59],[0,0,13,170,0,0,1,61,0,0,0,0,2,1,0,75,0,0,15,220,0,0,193,61,0,0,5,36,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,9,1,0,0,41,0,0,0,4,0,16,4,67,0,0,5,2,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,37,1,16,1,199,0,0,128,2,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,16,244,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,9,110,0,0,97,61],[0,0,0,8,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,3,118,0,0,97,61],[0,0,5,11,2,0,0,65,0,0,0,32,3,16,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,0,5,11,1,16,1,151,0,0,0,0,4,1,0,75,0,0,0,0,2,0,160,25,0,0,5,11,1,16,0,156],[0,0,0,0,2,3,192,25,0,0,0,0,1,2,0,75,0,0,1,39,0,0,193,61,0,0,0,6,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,2,1,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57],[0,0,0,0,2,33,0,75,0,0,1,39,0,0,193,61,0,0,0,0,1,1,0,75,0,0,3,118,0,0,193,61],[0,0,11,12,0,0,1,61,0,0,5,2,2,0,0,65,0,0,5,2,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,6,4,0,0,41,0,0,8,221,0,0,1,61,0,0,5,58,8,112,0,156,0,0,18,165,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,0,8,67,3,79,0,0,0,1,4,0,0,58],[0,0,0,0,4,71,4,54,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,132,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,8,128,1,151,0,0,0,248,6,96,2,16,0,0,0,0,6,134,1,159],[0,0,5,64,6,96,0,65,0,0,0,0,0,100,4,53,0,0,0,64,4,0,4,61,0,0,0,32,6,64,0,57],[0,0,0,0,8,7,4,51,0,0,0,0,9,8,0,75,0,0,16,19,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,0,10,105,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,121,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,16,12,0,0,65,61,0,0,0,0,7,104,0,25],[0,0,0,0,0,7,4,53,0,0,0,0,7,72,0,25,0,0,0,32,9,112,0,57,0,0,0,8,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,35,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,8,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,28,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,6,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,51,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,6,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,44,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,5,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,67,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,5,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,60,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,4,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,83,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,4,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,76,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,7,120,0,25,0,0,0,32,9,112,0,57,0,0,0,3,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,10,8,0,75,0,0,16,99,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,0,11,154,0,25,0,0,0,32,10,160,0,57,0,0,0,3,12,160,0,41,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,138,0,75,0,0,16,92,0,0,65,61,0,0,0,0,9,152,0,25],[0,0,0,0,0,9,4,53,0,0,0,0,5,83,3,79,0,0,0,0,3,120,0,25,0,0,0,31,7,32,1,143],[0,0,0,32,8,48,0,57,0,0,0,5,9,32,2,114,0,0,16,116,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59],[0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75,0,0,16,108,0,0,65,61],[0,0,0,0,10,7,0,75,0,0,16,131,0,0,97,61,0,0,0,5,9,144,2,16,0,0,0,0,5,149,3,79],[0,0,0,0,8,152,0,25,0,0,0,3,7,112,2,16,0,0,0,0,9,8,4,51,0,0,0,0,9,121,1,207],[0,0,0,0,9,121,2,47,0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47],[0,0,0,0,5,117,1,207,0,0,0,0,5,149,1,159,0,0,0,0,0,88,4,53,0,0,0,0,2,35,0,25],[0,0,0,32,5,32,0,57,0,0,0,0,0,5,4,53,0,0,0,0,3,1,4,51,0,0,0,0,7,3,0,75],[0,0,16,145,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,87,0,25,0,0,0,32,7,112,0,57],[0,0,0,0,9,23,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53,0,0,0,0,8,55,0,75],[0,0,16,138,0,0,65,61,0,0,0,0,1,83,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,66,0,73],[0,0,0,0,1,19,0,25,0,0,0,0,0,20,4,53,0,0,0,63,1,16,0,57,0,0,0,2,2,16,1,127],[0,0,0,0,1,66,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,5,10,3,16,0,156,0,0,18,165,0,0,33,61,0,0,0,1,2,32,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,5,2,1,0,0,65,0,0,5,2,2,96,0,156,0,0,0,0,6,1,128,25],[0,0,0,64,2,96,2,16,0,0,0,0,3,4,4,51,0,0,5,2,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,5,2,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,5,13,1,16,1,199],[0,0,128,16,2,0,0,57,20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,39,0,0,97,61],[0,0,0,2,3,0,3,103,0,0,0,0,1,1,4,59,0,8,0,0,0,1,0,29,0,0,0,10,1,0,0,41],[0,0,0,228,4,16,0,57,0,0,0,0,1,67,3,79,0,0,0,0,1,1,4,59,0,0,5,12,1,16,1,152],[0,5,0,0,0,4,0,29,0,0,16,212,0,0,193,61,0,0,0,128,1,64,0,138,0,0,0,0,2,19,3,79],[0,0,0,64,1,64,0,138,0,0,0,0,5,19,3,79,0,0,0,0,4,2,4,59,0,0,0,0,5,5,4,59],[0,0,0,0,98,69,0,169,0,0,0,0,6,5,0,75,0,0,16,202,0,0,97,61,0,0,0,0,101,82,0,217],[0,0,0,0,4,69,0,75,0,0,16,208,0,0,193,61,0,0,0,128,1,16,0,57,0,0,0,0,1,19,3,79],[0,0,0,0,1,1,4,59,0,6,0,0,0,33,0,30,0,0,16,208,0,0,65,61,0,0,16,217,0,0,1,61],[0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,0,65,0,0,1,61],[0,0,0,10,1,0,0,41,0,0,1,36,1,16,0,57,0,0,0,0,1,19,3,79,0,0,0,0,1,1,4,59],[0,6,0,0,0,1,0,29,0,0,5,78,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,7,1,0,0,41],[0,0,0,4,0,16,4,67,0,0,5,2,1,0,0,65,0,0,0,0,2,0,4,20,0,0,5,2,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,37,1,16,1,199,0,0,128,10,2,0,0,57],[20,1,19,242,0,0,4,15,0,0,0,1,2,32,1,144,0,0,16,244,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,6,1,16,0,107,0,0,16,245,0,0,161,61,0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57],[0,0,5,86,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,5,87,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,34,3,0,0,57,0,0,1,5,0,0,1,61],[0,0,0,0,0,1,4,47,0,0,0,0,4,0,0,49,0,0,0,10,1,64,0,106,0,0,0,35,2,16,0,138],[0,0,0,5,1,0,0,41,0,0,1,0,1,16,0,57,0,0,0,2,3,0,3,103,0,0,0,0,1,19,3,79],[0,0,0,0,1,1,4,59,0,0,5,11,5,0,0,65,0,0,0,0,6,33,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,5,11,2,32,1,151,0,0,5,11,7,16,1,151,0,0,0,0,8,39,0,75],[0,0,0,0,5,0,128,25,0,0,0,0,2,39,1,63,0,0,5,11,2,32,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,2,5,0,75,0,0,1,39,0,0,193,61,0,0,0,9,2,16,0,41,0,0,0,0,1,35,3,79],[0,0,0,0,1,1,4,59,0,0,5,10,5,16,0,156,0,0,1,39,0,0,33,61,0,0,0,0,5,20,0,73],[0,0,0,32,6,32,0,57,0,0,5,11,2,0,0,65,0,0,0,0,7,86,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,2,32,25,0,0,5,11,5,80,1,151,0,0,5,11,8,96,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,2,0,128,25,0,0,0,0,5,88,1,63,0,0,5,11,5,80,0,156,0,0,0,0,2,7,192,25],[0,0,0,0,2,2,0,75,0,0,1,39,0,0,193,61,0,0,0,63,2,16,0,57,0,0,0,32,5,0,0,138],[0,0,0,0,5,82,1,111,0,0,0,64,2,0,4,61,0,0,0,0,5,82,0,25,0,0,0,0,7,37,0,75],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,64,57,0,0,5,10,8,80,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,7,112,1,144,0,0,18,165,0,0,193,61,0,0,0,64,0,80,4,63,0,0,0,0,5,18,4,54],[0,0,0,0,7,97,0,25,0,0,0,0,4,71,0,75,0,0,1,39,0,0,33,61,0,0,0,0,4,99,3,79],[0,0,0,31,3,16,1,143,0,0,0,5,6,16,2,114,0,0,17,60,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,133,0,25,0,0,0,0,8,132,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,17,52,0,0,65,61],[0,0,0,0,7,3,0,75,0,0,17,75,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,4,100,3,79],[0,0,0,0,6,101,0,25,0,0,0,3,3,48,2,16,0,0,0,0,7,6,4,51,0,0,0,0,7,55,1,207],[0,0,0,0,7,55,2,47,0,0,0,0,4,4,4,59,0,0,1,0,3,48,0,137,0,0,0,0,4,52,2,47],[0,0,0,0,3,52,1,207,0,0,0,0,3,115,1,159,0,0,0,0,0,54,4,53,0,0,0,0,1,21,0,25],[0,0,0,0,0,1,4,53,0,0,0,64,1,0,4,61,0,0,0,0,3,2,4,51,0,0,0,65,3,48,0,140],[0,0,17,94,0,0,193,61,0,0,0,65,3,32,0,57,0,0,0,0,3,3,4,51,0,0,0,255,3,48,1,143],[0,0,0,29,4,48,0,138,0,0,0,3,6,0,0,138,0,0,0,0,4,100,0,75,0,0,17,100,0,0,33,61],[0,0,0,68,2,16,0,57,0,0,5,85,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,22,3,0,0,57,0,0,4,110,0,0,1,61,0,0,0,68,2,16,0,57,0,0,5,79,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,29,3,0,0,57,0,0,4,110,0,0,1,61],[0,0,0,0,4,5,4,51,0,0,0,64,2,32,0,57,0,0,0,0,2,2,4,51,0,0,5,80,5,32,0,156],[0,0,17,111,0,0,65,61,0,0,0,68,2,16,0,57,0,0,5,84,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,9,3,0,0,57,0,0,4,110,0,0,1,61,0,0,0,96,5,16,0,57],[0,0,0,0,0,37,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57],[0,0,0,0,0,50,4,53,0,0,0,8,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,0,0,0,4,53],[0,0,5,2,2,0,0,65,0,0,0,0,3,0,4,20,0,0,5,2,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,5,2,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,5,81,1,16,1,199,0,0,0,1,2,0,0,57,20,1,19,242,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,5,2,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,4,64,2,114],[0,0,17,149,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,70,0,75],[0,0,17,142,0,0,65,61,0,0,0,0,6,5,0,75,0,0,17,163,0,0,97,61,0,0,0,3,5,80,2,16],[0,0,0,5,4,64,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,101,1,159,0,0,0,0,0,84,4,53,0,1,0,0,0,3,0,31],[0,3,0,0,0,1,3,85,0,0,0,64,4,0,4,61,0,0,0,1,2,32,1,144,0,0,17,186,0,0,97,61],[0,0,0,0,1,0,4,51,0,0,5,12,1,16,1,151,0,0,0,7,2,16,0,108,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,192,57,0,0,0,0,1,1,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57],[0,0,0,0,1,18,1,160,0,0,5,82,1,0,0,65,0,0,0,0,1,0,192,25,0,0,0,0,0,20,4,53],[0,0,5,2,1,0,0,65,0,0,5,2,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16],[0,0,5,83,1,16,1,199,0,0,20,2,0,1,4,46,0,0,0,31,2,48,1,143,0,0,0,5,5,48,2,114],[0,0,17,198,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,17,190,0,0,65,61,0,0,0,0,6,2,0,75,0,0,17,213,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25,0,0,0,3,2,32,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,38,1,207,0,0,0,0,6,38,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,5,2,1,0,0,65,0,0,5,2,2,64,0,156,0,0,0,0,4,1,128,25],[0,0,0,64,1,64,2,16,0,0,6,74,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,17,229,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,17,222,0,0,65,61,0,0,0,0,5,4,0,75,0,0,17,243,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,20,3,0,1,4,48,0,0,0,56,8,64,0,140,0,0,18,69,0,0,65,61,0,0,0,32,9,64,2,112],[0,0,5,2,8,64,0,156,0,0,0,0,9,4,160,25,0,0,5,2,8,64,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,5,58,10,112,0,156,0,0,18,165,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,2,9,128,0,58],[0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159],[0,0,5,63,10,160,1,199,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,132,1,207,0,0,0,33,9,112,0,57,0,0,0,0,0,137,4,53,0,0,0,0,8,7,0,25],[0,0,18,86,0,0,1,61,0,0,0,56,8,64,0,140,0,0,18,145,0,0,65,61,0,0,0,32,9,64,2,112],[0,0,5,2,8,64,0,156,0,0,0,0,9,4,160,25,0,0,5,2,8,64,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,5,58,10,96,0,156,0,0,18,165,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,2,9,128,0,58],[0,0,0,0,9,150,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,12,17,0,0,97,61,0,0,5,59,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159],[0,0,5,63,10,160,1,199,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,132,1,207,0,0,0,33,9,96,0,57,0,0,0,0,0,137,4,53,0,0,0,0,8,6,0,25],[0,0,18,162,0,0,1,61,0,0,5,58,8,112,0,156,0,0,18,165,0,0,33,61,0,0,0,64,8,112,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,135,4,54],[0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,10,64,2,16,0,0,5,59,9,144,1,151,0,0,0,0,9,169,1,159,0,0,5,11,9,144,1,103],[0,0,0,0,0,152,4,53,0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61,0,0,5,58,9,112,0,156],[0,0,18,165,0,0,33,61,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,2,33,3,79],[0,0,0,1,12,0,0,58,0,0,0,0,9,199,4,54,0,0,0,0,2,32,3,80,0,0,0,0,11,2,4,59],[0,0,0,0,0,185,4,53,0,0,12,17,0,0,97,61,0,0,5,59,2,176,1,151,0,0,5,64,10,32,1,199],[0,0,0,0,0,169,4,53,0,0,0,0,9,6,4,51,0,0,0,0,9,73,0,25,0,0,0,0,10,8,4,51],[0,0,0,0,9,169,0,25,0,0,0,0,10,7,4,51,0,0,0,0,9,169,0,25,0,0,0,64,10,0,4,61],[0,0,5,10,9,144,1,151,0,0,0,56,13,144,0,140,0,0,18,225,0,0,65,61,0,0,0,32,13,144,2,112],[0,0,5,2,12,144,0,156,0,0,0,0,13,9,160,25,0,0,5,2,12,144,0,156,0,0,0,0,14,0,0,25],[0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140,0,0,0,0,12,14,160,25],[0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140,0,0,0,0,13,0,0,25],[0,0,0,1,13,0,32,57,0,0,5,58,14,160,0,156,0,0,18,165,0,0,33,61,0,0,0,0,12,220,1,159],[0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53],[0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,12,17,0,0,97,61,0,0,0,248,11,192,2,16],[0,0,0,0,2,43,1,159,0,0,5,65,2,32,1,199,0,0,0,0,0,45,4,53,0,0,0,3,2,192,2,16],[0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57,0,0,0,0,0,41,4,53],[0,0,18,238,0,0,1,61,0,0,5,58,8,96,0,156,0,0,18,165,0,0,33,61,0,0,0,64,8,96,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,134,4,54],[0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,12,17,0,0,97,61],[0,0,0,248,10,64,2,16,0,0,5,59,9,144,1,151,0,0,0,0,9,169,1,159,0,0,5,11,9,144,1,103],[0,0,0,0,0,152,4,53,0,0,0,0,8,6,0,25,0,0,0,64,6,0,4,61,0,0,5,58,9,96,0,156],[0,0,18,169,0,0,161,61,0,0,5,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,65,0,0,1,61,0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,2,33,3,79],[0,0,0,1,12,0,0,58,0,0,0,0,9,198,4,54,0,0,0,0,2,32,3,80,0,0,0,0,11,2,4,59],[0,0,0,0,0,185,4,53,0,0,12,17,0,0,97,61,0,0,5,59,2,176,1,151,0,0,5,64,10,32,1,199],[0,0,0,0,0,169,4,53,0,0,0,0,9,7,4,51,0,0,0,0,9,73,0,25,0,0,0,0,10,8,4,51],[0,0,0,0,9,169,0,25,0,0,0,0,10,6,4,51,0,0,0,0,9,169,0,25,0,0,0,64,10,0,4,61],[0,0,5,10,9,144,1,151,0,0,0,56,13,144,0,140,0,0,19,91,0,0,65,61,0,0,0,32,13,144,2,112],[0,0,5,2,12,144,0,156,0,0,0,0,13,9,160,25,0,0,5,2,12,144,0,156,0,0,0,0,14,0,0,25],[0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140,0,0,0,0,12,14,160,25],[0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140,0,0,0,0,13,0,0,25],[0,0,0,1,13,0,32,57,0,0,5,58,14,160,0,156,0,0,18,165,0,0,33,61,0,0,0,0,12,220,1,159],[0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53],[0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,12,17,0,0,97,61,0,0,0,248,11,192,2,16],[0,0,0,0,2,43,1,159,0,0,5,65,2,32,1,199,0,0,0,0,0,45,4,53,0,0,0,3,2,192,2,16],[0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57,0,0,0,0,0,41,4,53],[0,0,19,104,0,0,1,61,0,0,5,58,13,160,0,156,0,0,18,165,0,0,33,61,0,0,0,64,13,160,0,57],[0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53,0,0,0,0,0,202,4,53],[0,0,0,0,11,12,0,75,0,0,12,17,0,0,97,61,0,0,0,248,9,144,2,16,0,0,0,0,2,41,1,159],[0,0,5,64,2,32,0,65,0,0,0,0,0,45,4,53,0,0,0,64,2,0,4,61,0,0,0,32,9,32,0,57],[0,0,5,66,11,0,0,65,0,0,0,0,0,185,4,53,0,0,0,33,12,32,0,57,0,0,0,0,11,10,4,51],[0,0,0,0,13,11,0,75,0,0,18,254,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25],[0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53],[0,0,0,0,14,189,0,75,0,0,18,247,0,0,65,61,0,0,0,0,10,203,0,25,0,0,0,0,0,10,4,53],[0,0,0,0,10,43,0,25,0,0,0,33,12,160,0,57,0,0,0,0,11,6,4,51,0,0,0,0,13,11,0,75],[0,0,19,13,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57],[0,0,0,0,15,109,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75],[0,0,19,6,0,0,65,61,0,0,0,0,6,203,0,25,0,0,0,0,0,6,4,53,0,0,0,0,6,171,0,25],[0,0,0,33,11,96,0,57,0,0,0,0,10,8,4,51,0,0,0,0,12,10,0,75,0,0,19,28,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,140,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,172,0,75,0,0,19,21,0,0,65,61],[0,0,0,0,8,186,0,25,0,0,0,0,0,8,4,53,0,0,0,0,5,81,3,79,0,0,0,0,1,106,0,25],[0,0,0,31,6,64,1,143,0,0,0,33,8,16,0,57,0,0,0,5,10,64,2,114,0,0,19,45,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16,0,0,0,0,13,200,0,25,0,0,0,0,12,197,3,79],[0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53,0,0,0,1,11,176,0,57,0,0,0,0,12,171,0,75],[0,0,19,37,0,0,65,61,0,0,0,0,11,6,0,75,0,0,19,60,0,0,97,61,0,0,0,5,10,160,2,16],[0,0,0,0,5,165,3,79,0,0,0,0,8,168,0,25,0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51],[0,0,0,0,10,106,1,207,0,0,0,0,10,106,2,47,0,0,0,0,5,5,4,59,0,0,1,0,6,96,0,137],[0,0,0,0,5,101,2,47,0,0,0,0,5,101,1,207,0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53],[0,0,0,0,1,65,0,25,0,0,0,33,5,16,0,57,0,0,0,0,0,5,4,53,0,0,0,0,4,7,4,51],[0,0,0,0,6,4,0,75,0,0,19,74,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,8,86,0,25],[0,0,0,32,6,96,0,57,0,0,0,0,10,118,0,25,0,0,0,0,10,10,4,51,0,0,0,0,0,168,4,53],[0,0,0,0,8,70,0,75,0,0,19,67,0,0,65,61,0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53],[0,0,0,0,1,33,0,73,0,0,0,0,1,20,0,25,0,0,0,1,4,16,0,57,0,0,0,0,0,66,4,53],[0,0,0,64,1,16,0,57,0,0,0,0,3,49,1,111,0,0,0,0,1,35,0,25,0,0,0,0,3,49,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,5,10,4,16,0,156,0,0,18,165,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,19,212,0,0,97,61,0,0,18,165,0,0,1,61,0,0,5,58,13,160,0,156],[0,0,18,165,0,0,33,61,0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57],[0,0,0,0,0,189,4,53,0,0,0,0,0,202,4,53,0,0,0,0,11,12,0,75,0,0,12,17,0,0,97,61],[0,0,0,248,9,144,2,16,0,0,0,0,2,41,1,159,0,0,5,64,2,32,0,65,0,0,0,0,0,45,4,53],[0,0,0,64,2,0,4,61,0,0,0,32,9,32,0,57,0,0,5,13,11,0,0,65,0,0,0,0,0,185,4,53],[0,0,0,33,12,32,0,57,0,0,0,0,11,10,4,51,0,0,0,0,13,11,0,75,0,0,19,120,0,0,97,61],[0,0,0,0,13,0,0,25,0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25],[0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75,0,0,19,113,0,0,65,61],[0,0,0,0,10,203,0,25,0,0,0,0,0,10,4,53,0,0,0,0,10,43,0,25,0,0,0,33,12,160,0,57],[0,0,0,0,11,7,4,51,0,0,0,0,13,11,0,75,0,0,19,135,0,0,97,61,0,0,0,0,13,0,0,25],[0,0,0,0,14,205,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,125,0,25,0,0,0,0,15,15,4,51],[0,0,0,0,0,254,4,53,0,0,0,0,14,189,0,75,0,0,19,128,0,0,65,61,0,0,0,0,7,203,0,25],[0,0,0,0,0,7,4,53,0,0,0,0,7,171,0,25,0,0,0,33,11,112,0,57,0,0,0,0,10,8,4,51],[0,0,0,0,12,10,0,75,0,0,19,150,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,0,13,188,0,25],[0,0,0,32,12,192,0,57,0,0,0,0,14,140,0,25,0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53],[0,0,0,0,13,172,0,75,0,0,19,143,0,0,65,61,0,0,0,0,8,186,0,25,0,0,0,0,0,8,4,53],[0,0,0,0,5,81,3,79,0,0,0,0,1,122,0,25,0,0,0,31,7,64,1,143,0,0,0,33,8,16,0,57],[0,0,0,5,10,64,2,114,0,0,19,167,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16],[0,0,0,0,13,200,0,25,0,0,0,0,12,197,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53],[0,0,0,1,11,176,0,57,0,0,0,0,12,171,0,75,0,0,19,159,0,0,65,61,0,0,0,0,11,7,0,75],[0,0,19,182,0,0,97,61,0,0,0,5,10,160,2,16,0,0,0,0,5,165,3,79,0,0,0,0,8,168,0,25],[0,0,0,3,7,112,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,122,1,207,0,0,0,0,10,122,2,47],[0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47,0,0,0,0,5,117,1,207],[0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25,0,0,0,33,5,16,0,57],[0,0,0,0,0,5,4,53,0,0,0,0,4,6,4,51,0,0,0,0,7,4,0,75,0,0,19,196,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,0,8,87,0,25,0,0,0,32,7,112,0,57,0,0,0,0,10,103,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,168,4,53,0,0,0,0,8,71,0,75,0,0,19,189,0,0,65,61],[0,0,0,0,5,84,0,25,0,0,0,0,0,5,4,53,0,0,0,0,1,33,0,73,0,0,0,0,1,20,0,25],[0,0,0,1,4,16,0,57,0,0,0,0,0,66,4,53,0,0,0,64,1,16,0,57,0,0,0,0,3,49,1,111],[0,0,0,0,1,35,0,25,0,0,0,0,3,49,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,0,5,10,4,16,0,156,0,0,18,165,0,0,33,61,0,0,0,1,3,48,1,144,0,0,18,165,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,5,2,1,0,0,65,0,0,5,2,3,144,0,156,0,0,0,0,9,1,128,25],[0,0,0,64,3,144,2,16,0,0,0,0,2,2,4,51,0,0,5,2,4,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159,0,0,16,170,0,0,1,61,0,0,0,0,4,3,0,75],[0,0,19,233,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,36,0,25,0,0,0,0,6,20,0,25],[0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53,0,0,0,32,4,64,0,57,0,0,0,0,5,52,0,75],[0,0,19,226,0,0,65,61,0,0,0,0,1,35,0,25,0,0,0,0,0,1,4,53,0,0,0,0,0,1,4,45],[0,0,0,0,0,1,4,47,0,0,19,240,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,19,245,0,33,4,35,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,19,250,0,33,4,33],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,19,255,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,20,1,0,0,4,50,0,0,20,2,0,1,4,46,0,0,20,3,0,1,4,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,223,156,21,136],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,223,156,21,137],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,243,24,227],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,238,184,203,9],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,43,204,231],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,162,140,26,238],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[114,97,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[70,97,105,108,101,100,32,116,111,32,112,97,121,32,116,104,101,32,102,101,101,32,116,111,32,116,104,101,32,111,112,101],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[236,249,91,138,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[156,77,83,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[60,218,51,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[93,56,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[148,148,49,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[140,90,52,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[85,110,115,117,112,112,111,114,116,101,100,32,112,97,121,109,97,115,116,101,114,32,102,108,111,119,0,0,0,0,0,0],[221,98,237,62,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0,0,128,0,0,0,0,0,0,0,0],[9,94,167,179,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[83,97,102,101,69,82,67,50,48,58,32,108,111,119,45,108,101,118,101,108,32,99,97,108,108,32,102,97,105,108,101,100],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0,0],[83,97,102,101,69,82,67,50,48,58,32,97,112,112,114,111,118,101,32,102,114,111,109,32,110,111,110,45,122,101,114,111],[32,116,111,32,110,111,110,45,122,101,114,111,32,97,108,108,111,119,97,110,99,101,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,127],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,63],[111,116,32,115,117,99,99,101,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[83,97,102,101,69,82,67,50,48,58,32,69,82,67,50,48,32,111,112,101,114,97,116,105,111,110,32,100,105,100,32,110],[65,100,100,114,101,115,115,58,32,99,97,108,108,32,116,111,32,110,111,110,45,99,111,110,116,114,97,99,116,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,97,112,112,114,111,118,97,108,66,97,115,101,100,32,112,97,121,109,97,115,116,101,114,32,105,110,112,117],[116,32,109,117,115,116,32,98,101,32,97,116,32,108,101,97,115,116,32,54,56,32,98,121,116,101,115,32,108,111,110,103],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,101,32,115,116,97,110,100,97,114,100,32,112,97,121,109,97,115,116,101,114,32,105,110,112,117,116,32,109,117,115],[116,32,98,101,32,97,116,32,108,101,97,115,116,32,52,32,98,121,116,101,115,32,108,111,110,103,0,0,0,0,0,0],[225,35,156,216,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,160,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[69,110,99,111,100,105,110,103,32,117,110,115,117,112,112,111,114,116,101,100,32,116,120,0,0,0,0,0,0,0,0,0],[154,138,5,146,172,137,197,173,59,198,223,130,36,193,123,72,89,118,245,151,223,16,78,226,13,13,244,21,36,31,103,11],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,191],[0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[248,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[7,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[132,142,27,250,26,196,227,87,107,114,139,218,103,33,178,21,199,10,119,153,165,180,134,98,130,167,27,171,149,75,170,200],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,254,31],[194,248,120,113,118,184,172,107,247,33,91,74,220,193,224,105,191,74,184,45,154,177,223,5,165,122,145,212,37,147,91,110],[173,124,91,239,2,120,22,168,0,218,23,54,68,79,181,138,128,126,244,201,96,59,120,72,103,63,126,58,104,235,20,165],[25,180,83,206,69,170,170,243,163,0,245,169,236,149,134,155,79,40,171,16,67,11,87,46,226,24,195,166,165,224,125,111],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,95],[25,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[156,199,247,8,175,198,89,68,130,155,212,135,185,11,114,83,107,25,81,134,79,191,193,78,18,95,201,114,166,80,127,57],[83,105,103,110,97,116,117,114,101,32,108,101,110,103,116,104,32,105,115,32,105,110,99,111,114,114,101,99,116,0,0,0],[127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,93,87,110,115,87,164,80,29,223,233,47,70,104,27,32,161],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0],[32,43,204,231,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,118,97,108,105,100,32,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[118,32,105,115,32,110,101,105,116,104,101,114,32,50,55,32,110,111,114,32,50,56,0,0,0,0,0,0,0,0,0,0],[117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[78,111,116,32,101,110,111,117,103,104,32,98,97,108,97,110,99,101,32,102,111,114,32,102,101,101,32,43,32,118,97,108],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[205,226,41,223,135,157,189,123,19,91,210,22,87,91,13,13,139,233,20,214,167,167,41,134,204,148,77,212,186,226,50,198]],"predeployed_contracts":{"0x0000000000000000000000000000000000000001":[[0,0,0,1,2,32,1,144,0,0,0,32,0,0,193,61,0,0,0,96,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,12,5,32,0,65,0,0,0,64,3,16,3,112,0,0,0,0,3,3,4,59,0,0,0,12,6,48,0,65],[0,0,0,32,4,16,3,112,0,0,0,0,4,4,4,59,0,0,0,29,7,64,0,138,0,0,0,2,8,0,0,138],[0,0,0,0,7,135,0,75,0,0,0,30,0,0,65,61,0,0,0,13,6,96,0,156,0,0,0,30,0,0,65,61],[0,0,0,12,5,80,0,156,0,0,0,30,0,0,161,61,0,0,0,0,1,1,4,59,0,0,0,0,0,16,4,53],[0,0,0,27,1,64,0,138,0,0,0,32,0,16,4,63,0,0,0,64,0,48,4,63,0,0,0,96,0,32,4,63],[0,0,4,88,1,0,0,57,0,0,0,14,2,0,0,65,0,0,0,0,1,18,4,32,0,0,0,0,2,0,4,51],[0,0,0,0,1,18,1,112,0,0,0,37,0,0,193,61,0,0,0,0,1,0,0,25,0,0,0,40,0,1,4,46],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,11,1,0,0,65],[0,0,0,40,0,1,4,46,0,0,0,15,1,0,0,65,0,0,0,40,0,1,4,46,0,0,0,39,0,0,4,50],[0,0,0,40,0,1,4,46,0,0,0,41,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,69,81,35,25,80,183,95,196,64,45,161,115,47,201,190,191],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,69,81,35,25,80,183,95,196,64,45,161,115,47,201,190,192],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,4,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,32,0,0,0,0,0,0,0,0],[205,76,193,251,171,13,182,237,9,254,102,184,97,34,209,59,23,93,45,253,17,17,77,105,136,160,250,31,151,204,138,222]],"0x0000000000000000000000000000000000000006":[[0,4,0,0,0,0,0,2,0,0,0,1,2,32,1,144,0,0,0,17,0,0,193,61,0,0,0,96,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,0,64,3,16,3,112,0,0,0,0,3,3,4,59,0,0,0,0,5,50,1,159],[0,0,0,0,20,1,4,60,0,0,0,0,1,1,4,59,0,0,0,0,6,65,1,159,0,0,0,0,7,101,1,160],[0,0,0,22,0,0,193,61,0,0,0,0,0,0,4,53,0,0,0,32,0,0,4,63,0,0,0,141,1,0,0,65],[0,0,2,8,0,1,4,46,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,131,1,0,0,65,0,0,2,8,0,1,4,46,0,0,0,0,7,5,0,75,0,0,0,87,0,0,97,61],[0,0,0,0,7,6,0,75,0,0,0,87,0,0,193,61,0,0,0,132,1,48,0,156,0,0,0,30,0,0,33,61],[0,0,0,132,1,32,0,156,0,0,0,32,0,0,161,61,0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32],[0,0,0,0,1,3,0,75,0,0,0,133,65,48,0,209,0,0,0,1,4,64,192,57,0,0,0,134,81,48,0,209],[0,0,0,135,81,16,0,209,0,0,0,0,1,84,0,25,0,0,0,136,4,16,0,65,0,0,0,132,5,16,0,156],[0,0,0,0,4,1,160,25,0,0,0,0,81,68,0,170,0,0,0,1,5,80,192,57,0,0,0,137,97,16,0,209],[0,0,0,135,97,16,0,209,0,0,0,0,1,101,0,25,0,0,0,136,5,16,0,65,0,0,0,132,6,16,0,156],[0,0,0,0,5,1,160,25,0,0,0,0,65,69,0,170,0,0,0,1,4,64,192,57,0,0,0,0,5,2,0,75],[0,0,0,133,101,32,0,209,0,0,0,1,6,96,192,57,0,0,0,134,117,32,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,6,80,0,65,0,0,0,132,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,0,0,101,102,0,170,0,0,0,1,6,96,192,57,0,0,0,137,113,16,0,209,0,0,0,137,117,80,0,209],[0,0,0,135,113,16,0,209,0,0,0,0,1,116,0,25,0,0,0,135,84,80,0,209,0,0,0,0,4,86,0,25],[0,0,0,136,5,16,0,65,0,0,0,132,6,16,0,156,0,0,0,0,5,1,160,25,0,0,0,136,1,64,0,65],[0,0,0,132,6,64,0,156,0,0,0,0,1,4,160,25,0,0,0,138,4,0,0,65,0,0,0,139,6,0,0,65],[0,0,0,140,7,80,0,156,0,0,0,0,6,4,160,25,0,0,0,0,4,86,0,25,0,0,0,0,1,65,0,75],[0,0,0,83,0,0,97,61,0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32,0,0,0,0,0,48,4,53],[0,0,0,32,0,32,4,63,0,0,0,141,1,0,0,65,0,0,2,8,0,1,4,46,0,0,0,132,7,16,0,156],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,32,57,0,0,0,132,8,64,0,156,0,0,0,1,7,112,33,191],[0,0,0,0,6,6,0,75,0,0,0,153,0,0,97,61,0,0,0,0,5,5,0,75,0,0,0,153,0,0,193,61],[0,0,0,1,2,112,1,144,0,0,0,100,0,0,97,61,0,0,0,0,2,0,4,20,0,0,0,0,2,32,4,32],[0,0,0,0,2,4,0,75,0,0,0,133,50,64,0,209,0,0,0,1,3,48,192,57,0,0,0,134,82,64,0,209],[0,0,0,135,82,32,0,209,0,0,0,0,2,83,0,25,0,0,0,136,3,32,0,65,0,0,0,132,5,32,0,156],[0,0,0,0,3,2,160,25,0,0,0,0,82,51,0,170,0,0,0,1,5,80,192,57,0,0,0,137,98,32,0,209],[0,0,0,135,98,32,0,209,0,0,0,0,2,101,0,25,0,0,0,136,5,32,0,65,0,0,0,132,6,32,0,156],[0,0,0,0,5,2,160,25,0,0,0,0,50,53,0,170,0,0,0,1,3,48,192,57,0,0,0,0,5,1,0,75],[0,0,0,133,101,16,0,209,0,0,0,1,6,96,192,57,0,0,0,134,117,16,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,6,80,0,65,0,0,0,132,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,0,0,101,102,0,170,0,0,0,1,6,96,192,57,0,0,0,137,114,32,0,209,0,0,0,137,117,80,0,209],[0,0,0,135,114,32,0,209,0,0,0,0,2,115,0,25,0,0,0,135,83,80,0,209,0,0,0,0,3,86,0,25],[0,0,0,136,5,32,0,65,0,0,0,132,6,32,0,156,0,0,0,0,5,2,160,25,0,0,0,136,2,48,0,65],[0,0,0,132,6,48,0,156,0,0,0,0,2,3,160,25,0,0,0,138,3,0,0,65,0,0,0,139,6,0,0,65],[0,0,0,140,7,80,0,156,0,0,0,0,6,3,160,25,0,0,0,0,3,86,0,25,0,0,0,0,2,50,0,75],[0,0,0,151,0,0,97,61,0,0,0,0,2,0,4,20,0,0,0,0,2,32,4,32,0,0,0,0,0,64,4,53],[0,0,1,193,0,0,1,61,0,0,0,1,5,112,1,144,0,0,0,157,0,0,97,61,0,0,0,0,5,0,4,20],[0,0,0,0,5,80,4,32,0,0,0,132,5,48,0,156,0,0,0,161,0,0,33,61,0,0,0,135,5,32,0,156],[0,0,0,163,0,0,65,61,0,0,0,0,5,0,4,20,0,0,0,0,5,80,4,32,0,0,0,135,5,0,0,65],[0,0,0,0,6,21,0,73,0,0,0,135,103,96,1,42,0,0,0,0,7,52,0,75,0,0,0,241,0,0,193,61],[0,0,0,0,6,38,0,75,0,0,0,241,0,0,193,61,0,0,0,0,3,4,0,75,0,0,0,133,83,64,0,209],[0,0,0,1,5,80,192,57,0,0,0,134,67,64,0,209,0,0,0,135,67,48,0,209,0,0,0,0,3,69,0,25],[0,0,0,136,4,48,0,65,0,0,0,132,5,48,0,156,0,0,0,0,4,3,160,25,0,0,0,0,83,68,0,170],[0,0,0,1,5,80,192,57,0,0,0,137,99,48,0,209,0,0,0,135,99,48,0,209,0,0,0,0,3,101,0,25],[0,0,0,136,5,48,0,65,0,0,0,132,6,48,0,156,0,0,0,0,5,3,160,25,0,0,0,0,52,69,0,170],[0,0,0,1,3,48,192,57,0,0,0,0,5,2,0,75,0,0,0,133,101,32,0,209,0,0,0,1,6,96,192,57],[0,0,0,134,82,32,0,209,0,0,0,135,82,32,0,209,0,0,0,0,2,86,0,25,0,0,0,136,5,32,0,65],[0,0,0,132,6,32,0,156,0,0,0,0,5,2,160,25,0,0,0,0,82,85,0,170,0,0,0,1,5,80,192,57],[0,0,0,0,6,1,0,75,0,0,0,133,118,16,0,209,0,0,0,1,7,112,192,57,0,0,0,134,97,16,0,209],[0,0,0,135,97,16,0,209,0,0,0,0,1,103,0,25,0,0,0,136,6,16,0,65,0,0,0,132,7,16,0,156],[0,0,0,0,6,1,160,25,0,0,0,0,97,102,0,170,0,0,0,1,6,96,192,57,0,0,0,137,116,64,0,209],[0,0,0,137,114,32,0,209,0,0,0,135,114,32,0,209,0,0,0,0,2,117,0,25,0,0,0,137,21,16,0,209],[0,0,0,135,65,64,0,209,0,0,0,0,1,67,0,25,0,0,0,136,3,16,0,65,0,0,0,132,4,16,0,156],[0,0,0,0,3,1,160,25,0,0,0,136,1,32,0,65,0,0,0,132,4,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,135,66,80,0,209,0,0,0,0,2,70,0,25,0,0,0,136,4,32,0,65,0,0,0,132,5,32,0,156],[0,0,0,0,4,2,160,25,0,0,0,138,2,0,0,65,0,0,0,139,5,0,0,65,0,0,0,140,6,48,0,156],[0,0,0,0,5,2,160,25,0,0,0,0,2,53,0,25,0,0,0,0,3,36,0,75,0,0,0,238,0,0,193,61],[0,0,0,0,1,33,0,75,0,0,0,13,0,0,97,61,0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32],[0,0,0,13,0,0,1,61,0,0,0,0,5,37,0,73,0,0,0,135,86,80,1,42,0,0,0,0,6,52,0,75],[0,0,0,251,0,0,193,61,0,0,0,0,5,81,0,75,0,0,0,251,0,0,97,61,0,0,0,0,5,33,0,75],[0,0,0,251,0,0,97,61,0,0,0,0,5,0,4,20,0,0,0,0,5,80,4,32,0,0,0,0,5,4,0,75],[0,0,0,133,101,64,0,209,0,0,0,1,6,96,192,57,0,0,0,134,117,64,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,12,80,0,65,0,0,0,132,6,80,0,156,0,0,0,0,12,5,160,25],[0,0,0,0,101,204,0,170,0,0,0,1,6,96,192,57,0,0,0,137,117,80,0,209,0,0,0,135,117,80,0,209],[0,0,0,0,5,118,0,25,0,0,0,136,6,80,0,65,0,0,0,132,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,0,0,101,198,0,170,0,0,0,1,6,96,192,57,0,0,0,0,7,1,0,75,0,0,0,133,135,16,0,209],[0,0,0,1,8,128,192,57,0,0,0,134,151,16,0,209,0,0,0,135,151,112,0,209,0,0,0,0,7,152,0,25],[0,0,0,136,13,112,0,65,0,0,0,132,8,112,0,156,0,0,0,0,13,7,160,25,0,0,0,0,135,221,0,170],[0,0,0,1,8,128,192,57,0,0,0,137,149,80,0,209,0,0,0,137,151,112,0,209,0,0,0,135,149,80,0,209],[0,0,0,0,5,150,0,25,0,0,0,135,118,112,0,209,0,0,0,0,6,120,0,25,0,0,0,136,8,80,0,65],[0,0,0,132,7,80,0,156,0,0,0,0,8,5,160,25,0,0,0,136,5,96,0,65,0,0,0,132,7,96,0,156],[0,0,0,0,5,6,160,25,0,0,0,138,7,0,0,65,0,0,0,139,6,0,0,65,0,0,0,140,9,128,0,156],[0,0,0,0,9,7,0,25,0,0,0,0,9,6,32,25,0,0,0,0,8,137,0,25,0,0,0,0,4,52,0,75],[0,4,0,0,0,12,0,29,0,0,1,96,0,0,193,61,0,0,0,0,1,33,0,75,0,0,1,96,0,0,193,61],[0,3,0,0,0,13,0,29,0,0,0,0,1,133,0,75,0,0,1,53,0,0,97,61,0,0,0,0,1,0,4,20],[0,0,0,0,1,16,4,32,0,0,0,0,1,12,0,25,0,0,0,0,2,12,0,25,2,7,1,204,0,0,4,15],[0,0,0,135,33,16,1,42,0,0,0,1,1,32,2,16,0,0,0,135,49,16,1,42,0,0,0,0,1,35,0,25],[0,0,0,135,18,16,1,42,0,0,0,3,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,1,2,48,2,16],[0,0,0,135,35,32,1,42,2,7,1,213,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,0,2,1,0,25],[2,7,1,204,0,0,4,15,0,0,0,4,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,1,2,48,2,16],[0,0,0,135,66,32,1,42,0,0,0,135,5,0,0,65,0,0,0,0,2,69,0,73,0,0,0,135,66,32,1,42],[0,0,0,135,33,16,1,42,0,0,0,0,1,66,0,25,0,0,0,135,33,16,1,42,0,4,0,0,0,2,0,29],[0,0,0,0,1,37,0,73,0,0,0,135,33,16,1,42,0,0,0,0,1,50,0,25,0,0,0,135,33,16,1,42],[0,0,0,2,1,0,0,41,2,7,1,204,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,4,1,0,0,41],[2,7,1,196,0,0,4,15,0,0,0,135,3,0,0,65,0,0,0,3,2,48,0,106,0,0,0,135,50,32,1,42],[0,0,0,2,2,0,0,41,0,0,0,135,66,32,1,42,0,0,0,0,2,52,0,25,0,0,1,187,0,0,1,61],[0,0,0,0,1,3,0,75,0,0,0,133,65,48,0,209,0,0,0,1,4,64,192,57,0,0,0,134,49,48,0,209],[0,0,0,135,49,16,0,209,0,0,0,0,1,52,0,25,0,0,0,136,3,16,0,65,0,0,0,132,4,16,0,156],[0,0,0,0,3,1,160,25,0,0,0,0,65,51,0,170,0,0,0,1,4,64,192,57,0,0,0,137,145,16,0,209],[0,0,0,135,145,16,0,209,0,0,0,0,1,148,0,25,0,0,0,136,4,16,0,65,0,0,0,132,9,16,0,156],[0,0,0,0,4,1,160,25,0,0,0,0,148,52,0,170,0,0,0,1,9,144,192,57,0,0,0,0,1,2,0,75],[0,0,0,133,161,32,0,209,0,0,0,1,10,160,192,57,0,0,0,134,33,32,0,209,0,0,0,135,33,16,0,209],[0,0,0,0,2,42,0,25,0,0,0,136,1,32,0,65,0,0,0,132,10,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,0,162,17,0,170,0,0,0,1,10,160,192,57,0,0,0,137,180,64,0,209,0,0,0,137,178,32,0,209],[0,0,0,135,180,64,0,209,0,0,0,0,4,185,0,25,0,0,0,135,146,32,0,209,0,0,0,0,9,154,0,25],[0,0,0,136,2,64,0,65,0,0,0,132,10,64,0,156,0,0,0,0,2,4,160,25,0,0,0,136,4,144,0,65],[0,0,0,132,10,144,0,156,0,0,0,0,4,9,160,25,0,0,0,140,9,32,0,156,0,0,0,0,6,7,160,25],[0,0,0,0,5,133,0,75,0,0,1,145,0,0,193,61,0,0,0,0,2,38,0,25,0,0,0,0,2,36,0,75],[0,0,1,147,0,0,97,61,0,0,0,0,2,0,4,20,0,0,0,0,2,32,4,32,0,0,0,135,5,0,0,65],[0,0,0,0,2,213,0,73,0,0,0,135,66,32,1,42,0,3,0,0,0,4,0,29,0,0,0,135,33,16,1,42],[0,0,0,0,1,66,0,25,0,0,0,135,18,16,1,42,0,0,0,0,2,197,0,73,0,0,0,135,66,32,1,42],[0,0,0,135,50,48,1,42,0,1,0,0,0,3,0,29,0,0,0,0,2,67,0,25,0,0,0,135,35,32,1,42],[2,7,1,213,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,0,2,1,0,25,2,7,1,204,0,0,4,15],[0,0,0,4,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,1,2,48,0,41,0,0,0,135,66,32,1,42],[0,0,0,135,5,0,0,65,0,0,0,0,2,69,0,73,0,0,0,135,66,32,1,42,0,0,0,135,33,16,1,42],[0,0,0,0,1,66,0,25,0,0,0,135,33,16,1,42,0,4,0,0,0,2,0,29,0,0,0,0,1,37,0,73],[0,0,0,135,33,16,1,42,0,0,0,0,1,50,0,25,0,0,0,135,33,16,1,42,0,0,0,2,1,0,0,41],[2,7,1,204,0,0,4,15,0,2,0,0,0,1,0,29,0,0,0,4,1,0,0,41,2,7,1,196,0,0,4,15],[0,0,0,2,2,0,0,41,0,0,0,135,50,32,1,42,0,0,0,3,2,48,0,41,0,0,0,135,35,32,1,42],[0,4,0,0,0,1,0,29,0,0,0,0,1,2,0,25,2,7,1,196,0,0,4,15,0,0,0,4,2,0,0,41],[0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,141,1,0,0,65,0,0,2,8,0,1,4,46],[0,0,0,0,2,1,0,75,0,0,0,137,33,16,0,209,0,0,0,135,33,16,0,209,0,0,0,1,2,32,192,57],[0,0,0,136,1,32,0,65,0,0,0,132,3,32,0,156,0,0,0,0,1,2,160,25,0,0,0,0,0,1,4,45],[0,0,0,0,33,18,0,170,0,0,0,1,2,32,192,57,0,0,0,137,49,16,0,209,0,0,0,135,49,16,0,209],[0,0,0,0,2,50,0,25,0,0,0,136,1,32,0,65,0,0,0,132,3,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,0,0,1,4,45,0,0,0,133,3,0,0,65,0,0,0,1,4,32,0,140,0,0,1,254,0,0,97,61],[0,0,0,135,4,0,0,65,0,0,0,133,3,0,0,65,0,0,0,0,5,0,0,25,0,0,0,1,6,32,1,144],[0,0,1,227,0,0,193,61,0,0,0,1,6,48,1,144,0,0,0,135,3,48,192,65,0,0,0,2,6,32,1,144],[0,0,0,1,2,32,2,112,0,0,0,1,3,48,2,112,0,0,1,221,0,0,97,61,0,0,0,1,6,64,1,144],[0,0,1,235,0,0,193,61,0,0,0,1,6,80,1,144,0,0,0,135,5,80,192,65,0,0,0,2,6,64,1,144],[0,0,0,1,4,64,2,112,0,0,0,1,5,80,2,112,0,0,1,229,0,0,97,61,0,0,0,0,6,36,0,75],[0,0,1,243,0,0,161,61,0,0,0,135,6,80,0,65,0,0,0,0,7,53,0,75,0,0,0,0,6,5,128,25],[0,0,0,0,5,54,0,73,0,0,0,0,4,36,0,73,0,0,1,248,0,0,1,61,0,0,0,135,6,48,0,65],[0,0,0,0,7,83,0,75,0,0,0,0,6,3,128,25,0,0,0,0,3,86,0,73,0,0,0,0,2,66,0,73],[0,0,0,1,6,32,0,140,0,0,1,252,0,0,97,61,0,0,0,1,6,64,0,140,0,0,1,219,0,0,193,61],[0,0,0,1,2,32,0,140,0,0,0,0,3,5,192,25,0,0,0,0,33,19,0,170,0,0,0,1,2,32,192,57],[0,0,0,137,49,16,0,209,0,0,0,135,49,16,0,209,0,0,0,0,2,50,0,25,0,0,0,136,1,32,0,65],[0,0,0,132,3,32,0,156,0,0,0,0,1,2,160,25,0,0,0,0,0,1,4,45,0,0,2,7,0,0,4,50],[0,0,2,8,0,1,4,46,0,0,2,9,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,70],[6,216,159,113,202,184,53,31,71,171,30,255,10,65,127,246,181,231,25,17,212,69,1,251,243,44,252,91,83,138,250,137],[74,71,70,38,35,160,74,122,176,116,165,134,128,115,1,58,233,101,225,118,124,212,192,134,243,174,216,161,155,249,14,81],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,71],[207,155,177,141,30,206,95,214,71,175,186,73,126,126,167,162,104,126,149,110,151,142,53,114,195,223,115,233,39,131,2,185],[245,122,34,183,145,136,140,107,216,175,203,208,24,51,218,128,158,222,125,101,30,202,106,201,135,210,7,130,228,134,99,137],[42,31,103,68,206,23,157,142,51,75,234,78,105,107,210,132,31,106,193,122,225,85,33,185,122,23,202,169,80,173,40,215],[249,187,24,209,236,229,253,100,122,251,164,151,231,234,122,38,135,233,86,233,120,227,87,44,61,247,62,146,120,48,43,144],[6,68,231,46,19,26,2,155,133,4,91,104,24,21,133,217,120,22,169,22,135,28,168,211,194,8,193,109,135,207,212,111],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[7,155,177,253,3,237,92,151,14,41,125,66,188,24,151,228,93,136,135,3,202,158,108,195,48,138,79,213,56,163,134,170]],"0x000000000000000000000000000000000000800d":[[0,5,0,0,0,0,0,2,0,0,0,0,0,4,0,31,0,1,0,0,0,5,0,31,0,2,0,0,0,6,0,31],[0,3,0,0,0,7,0,31,0,4,0,0,0,1,3,85,0,0,0,96,1,16,2,112,0,0,0,20,1,16,1,151],[0,0,0,1,4,32,1,144,0,0,0,69,0,0,193,61,0,0,0,2,2,32,1,144,0,0,0,67,0,0,97,61],[0,0,0,5,2,48,0,140,0,0,0,67,0,0,129,61,0,0,0,32,2,16,2,16,0,0,0,0,2,35,0,25],[0,0,0,1,2,32,0,57,0,0,0,0,4,0,4,17,0,0,0,0,0,66,4,31,0,0,0,1,2,48,0,140],[0,0,0,33,0,0,161,61,0,0,0,2,2,48,0,140,0,0,0,41,0,0,97,61,0,0,0,3,2,48,0,140],[0,0,0,46,0,0,97,61,0,0,0,4,2,48,0,140,0,0,0,67,0,0,193,61,0,0,0,1,2,0,0,49],[0,0,0,0,3,0,0,49,0,0,0,0,0,35,4,30,0,0,0,3,2,0,0,49,0,0,0,2,3,0,0,49],[0,0,0,43,0,0,1,61,0,0,0,0,2,3,0,75,0,0,0,54,0,0,97,61,0,0,0,1,2,48,0,140],[0,0,0,67,0,0,193,61,0,0,0,4,2,0,3,103,0,0,0,0,2,2,4,59,0,0,0,0,3,0,0,49],[0,0,0,52,0,0,1,61,0,0,0,1,2,0,0,49,0,0,0,0,3,0,0,49,0,0,0,0,0,35,4,30],[0,0,0,0,3,0,0,25,0,0,0,54,0,0,1,61,0,0,0,1,2,0,0,49,0,0,0,0,3,0,0,49],[0,0,0,0,0,35,4,30,0,0,0,4,2,0,3,103,0,0,0,0,2,2,4,59,0,0,0,2,3,0,0,49],[0,0,0,0,0,35,4,30,0,0,0,32,3,0,0,57,0,0,0,0,2,19,0,75,0,0,0,65,0,0,129,61],[0,0,0,32,2,48,0,57,0,0,0,4,2,32,3,103,0,0,0,4,4,48,3,103,0,0,0,0,4,4,4,59],[0,0,0,0,2,2,4,59,0,0,0,0,0,36,4,30,0,0,0,64,3,48,0,57,0,0,0,0,2,19,0,75],[0,0,0,56,0,0,65,61,0,0,0,0,1,0,0,25,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25],[0,0,0,76,0,1,4,48,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,21,1,0,0,65,0,0,0,75,0,1,4,46,0,0,0,74,0,0,4,50,0,0,0,75,0,1,4,46],[0,0,0,76,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[180,184,165,48,127,13,205,253,29,139,217,234,142,173,226,137,254,133,108,230,229,7,36,30,205,42,49,201,117,98,142,148]],"0x000000000000000000000000000000000000800a":[[0,5,0,0,0,0,0,2,0,0,0,128,3,0,0,57,0,0,0,64,0,48,4,63,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,215,3,48,1,151,0,0,0,1,2,32,1,144,0,0,0,36,0,0,193,61],[0,0,0,4,2,48,0,140,0,0,3,10,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,0,217,4,32,0,156,0,0,0,44,0,0,161,61,0,0,0,218,4,32,0,156,0,0,0,56,0,0,161,61],[0,0,0,219,4,32,0,156,0,0,0,149,0,0,97,61,0,0,0,220,4,32,0,156,0,0,1,234,0,0,97,61],[0,0,0,221,2,32,0,156,0,0,3,10,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,3,10,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,3,10,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,229,1,16,1,151,0,0,0,0,0,16,4,53],[0,0,0,32,0,0,4,63,0,0,0,0,1,0,0,25,3,88,3,60,0,0,4,15,0,0,0,54,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,10,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,216,1,0,0,65,0,0,3,89,0,1,4,46],[0,0,0,224,4,32,0,156,0,0,0,96,0,0,33,61,0,0,0,227,1,32,0,156,0,0,1,166,0,0,97,61],[0,0,0,228,1,32,0,156,0,0,3,10,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,10,0,0,193,61,0,0,0,1,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,231,0,0,1,61],[0,0,0,222,4,32,0,156,0,0,1,175,0,0,97,61,0,0,0,223,2,32,0,156,0,0,3,10,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,10,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,96,2,32,0,140,0,0,3,10,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,4,2,4,59],[0,0,0,229,2,64,0,156,0,0,3,10,0,0,33,61,0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,229,5,32,1,151,0,0,0,229,2,32,0,156,0,0,3,10,0,0,33,61,0,0,0,0,2,0,4,17],[0,0,0,68,1,16,3,112,0,0,0,0,3,1,4,59,0,0,128,6,1,32,0,140,0,0,2,9,0,0,97,61],[0,0,0,9,1,0,0,138,0,0,0,0,1,18,1,111,0,0,128,1,1,16,0,140,0,0,2,9,0,0,97,61],[0,0,0,240,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,62,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,241,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,0,242,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,243,1,0,0,65,0,0,3,90,0,1,4,48],[0,0,0,225,4,32,0,156,0,0,1,227,0,0,97,61,0,0,0,226,2,32,0,156,0,0,3,10,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,10,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,64,2,32,0,140,0,0,3,10,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,4,2,4,59],[0,0,0,229,2,64,0,156,0,0,3,10,0,0,33,61,0,0,0,36,1,16,3,112,0,0,0,0,5,1,4,59],[0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,1,255,0,0,193,61,0,0,0,1,1,0,0,57],[0,0,0,0,3,1,4,26,0,0,0,0,2,83,0,25,0,0,0,0,3,50,0,75,0,0,0,0,3,0,0,25],[0,0,0,1,3,0,64,57,0,0,0,1,3,48,1,144,0,0,0,145,0,0,193,61,0,4,0,0,0,5,0,29],[0,0,0,0,0,33,4,27,0,0,0,0,0,64,4,53,0,0,0,32,0,0,4,63,0,0,0,215,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,0,5,0,0,0,4,0,29,3,88,3,83,0,0,4,15],[0,0,0,5,5,0,0,41,0,0,0,1,2,32,1,144,0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,4,26,0,0,0,4,3,0,0,41,0,0,0,0,2,50,0,26,0,0,0,145,0,0,65,61],[0,0,2,194,0,0,1,61,0,0,0,250,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,1,224,0,0,1,61,0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140,0,0,3,10,0,0,65,61],[0,0,0,4,2,16,3,112,0,0,0,0,8,2,4,59,0,0,0,229,2,128,0,156,0,0,3,10,0,0,33,61],[0,0,0,36,2,16,3,112,0,0,0,0,4,2,4,59,0,0,0,233,2,64,0,156,0,0,3,10,0,0,33,61],[0,0,0,35,2,64,0,57,0,0,0,234,5,0,0,65,0,0,0,0,6,50,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,0,234,2,32,1,151,0,0,0,0,7,2,0,75,0,0,0,0,5,0,128,25],[0,0,0,234,2,32,0,156,0,0,0,0,5,6,192,25,0,0,0,0,2,5,0,75,0,0,3,10,0,0,193,61],[0,0,0,4,5,64,0,57,0,0,0,0,2,81,3,79,0,0,0,0,2,2,4,59,0,0,0,233,6,32,0,156],[0,0,1,221,0,0,33,61,0,0,0,191,6,32,0,57,0,0,0,32,9,0,0,138,0,0,0,0,6,150,1,111],[0,0,0,233,7,96,0,156,0,0,1,221,0,0,33,61,0,0,0,64,0,96,4,63,0,0,0,128,0,32,4,63],[0,0,0,0,4,36,0,25,0,0,0,36,4,64,0,57,0,0,0,0,3,52,0,75,0,0,3,10,0,0,33,61],[0,0,0,32,3,80,0,57,0,0,0,0,1,49,3,79,0,0,0,31,3,32,1,143,0,0,0,5,4,32,2,114],[0,0,0,202,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,160,6,96,0,57,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,69,0,75,0,0,0,194,0,0,65,61,0,4,0,0,0,9,0,29,0,5,0,0,0,8,0,29],[0,0,0,0,5,3,0,75,0,0,0,219,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79],[0,0,0,3,3,48,2,16,0,0,0,160,4,64,0,57,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,0,160,1,32,0,57],[0,0,0,0,0,1,4,53,0,0,0,0,1,0,4,22,0,3,0,0,0,1,0,29,0,0,0,0,1,0,4,16],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,215,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,235,1,16,1,199],[0,0,128,16,2,0,0,57,3,88,3,83,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,5,4,0,0,41],[0,0,0,4,7,0,0,41,0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,1,4,26],[0,0,0,3,9,0,0,41,0,0,0,0,2,146,0,73,0,0,0,0,0,33,4,27,0,0,0,1,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,0,0,2,146,0,73,0,0,0,0,0,33,4,27,0,0,0,236,2,0,0,65],[0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,96,2,64,2,16],[0,0,0,36,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,0,8,0,4,17,0,0,0,96,2,128,2,16],[0,0,0,88,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,56,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,108,3,16,0,57,0,0,0,128,2,0,4,61,0,0,0,0,4,2,0,75,0,0,1,16,0,0,97,61],[0,0,0,0,4,0,0,25,0,0,0,0,5,52,0,25,0,0,0,160,6,64,0,57,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,32,4,64,0,57,0,0,0,0,5,36,0,75,0,0,1,9,0,0,65,61],[0,0,0,0,3,50,0,25,0,0,0,0,0,3,4,53,0,0,0,76,3,32,0,57,0,0,0,0,0,49,4,53],[0,0,0,139,2,32,0,57,0,0,0,0,2,114,1,111,0,0,0,0,10,18,0,25,0,0,0,0,2,42,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,0,233,3,160,0,156,0,0,1,221,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,1,221,0,0,193,61,0,1,0,0,0,8,0,29,0,0,0,64,0,160,4,63],[0,0,0,237,2,0,0,65,0,0,0,0,0,42,4,53,0,0,0,4,2,160,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,0,2,1,4,51,0,0,0,36,3,160,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,3,160,0,57,0,0,0,0,4,2,0,75,0,0,1,51,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,20,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,1,44,0,0,65,61,0,0,0,0,1,50,0,25],[0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,0,1,113,1,111,0,0,0,215,2,0,0,65],[0,0,0,215,3,160,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,10,64,25,0,0,0,64,3,48,2,16],[0,0,0,68,1,16,0,57,0,0,0,215,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57,0,2,0,0,0,10,0,29],[3,88,3,78,0,0,4,15,0,0,0,2,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,215,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,1,92,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,1,84,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,1,107,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,3,12,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,162,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,0,233,4,16,0,156],[0,0,0,5,4,0,0,41,0,0,0,3,5,0,0,41,0,0,1,221,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,1,221,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,32,2,48,0,140,0,0,3,10,0,0,65,61],[0,0,0,32,2,16,0,57,0,0,0,64,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,0,0,81,4,53],[0,0,0,64,3,16,0,57,0,0,0,128,2,0,4,61,0,0,0,0,0,35,4,53,0,0,0,96,3,16,0,57],[0,0,0,229,6,64,1,151,0,0,0,0,4,2,0,75,0,0,1,143,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,52,0,25,0,0,0,160,7,64,0,57,0,0,0,0,7,7,4,51,0,0,0,0,0,117,4,53],[0,0,0,32,4,64,0,57,0,0,0,0,5,36,0,75,0,0,1,136,0,0,65,61,0,0,0,0,3,50,0,25],[0,0,0,0,0,3,4,53,0,0,0,127,2,32,0,57,0,0,0,4,2,32,1,127,0,0,0,215,3,0,0,65],[0,0,0,215,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,64,1,16,2,16,0,0,0,215,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20],[0,0,0,215,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,0,238,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57,0,0,0,239,4,0,0,65],[0,0,0,1,5,0,0,41,0,0,3,5,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,10,0,0,193,61,0,0,0,192,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,5,1,0,0,57],[0,0,0,128,0,16,4,63,0,0,0,255,1,0,0,65,0,0,1,242,0,0,1,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,3,10,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,4,1,4,59],[0,0,0,229,1,64,0,156,0,0,3,10,0,0,33,61,0,0,0,0,1,0,4,22,0,4,0,0,0,1,0,29],[0,0,0,0,1,0,4,16,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,215,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,0,5,0,0,0,4,0,29,3,88,3,83,0,0,4,15],[0,0,0,5,4,0,0,41,0,0,0,1,2,32,1,144,0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,4,26,0,0,0,4,5,0,0,41,0,0,0,0,2,82,0,73,0,0,0,0,0,33,4,27],[0,0,0,1,1,0,0,57,0,0,0,0,2,1,4,26,0,0,0,0,2,82,0,73,0,0,0,0,0,33,4,27],[0,0,0,236,2,0,0,65,0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57,0,0,0,0,0,35,4,53],[0,0,0,96,2,64,2,16,0,0,0,36,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,56,2,16,0,57],[0,0,0,0,0,82,4,53,0,0,0,56,2,0,0,57,0,0,0,0,0,33,4,53,0,0,0,248,2,16,0,156],[0,0,2,47,0,0,65,61,0,0,0,250,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,0,251,1,0,0,65,0,0,3,90,0,1,4,48,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,10,0,0,193,61,0,0,0,18,1,0,0,57,0,0,0,128,0,16,4,63],[0,0,0,230,1,0,0,65,0,0,3,89,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,10,0,0,193,61,0,0,0,192,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,3,1,0,0,57],[0,0,0,128,0,16,4,63,0,0,0,231,1,0,0,65,0,0,0,160,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,192,0,16,4,63,0,0,0,128,1,0,0,57,0,0,0,224,2,0,0,57,3,88,3,41,0,0,4,15],[0,0,0,192,1,16,0,138,0,0,0,215,2,0,0,65,0,0,0,215,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,96,1,16,2,16,0,0,0,232,1,16,1,199,0,0,3,89,0,1,4,46,0,0,0,240,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,252,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,253,1,0,0,65],[0,0,3,90,0,1,4,48,0,4,0,0,0,3,0,29,0,0,0,0,0,64,4,53,0,0,0,32,0,0,4,63],[0,0,0,215,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,215,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,0,5,0,0,0,4,0,29],[0,3,0,0,0,5,0,29,3,88,3,83,0,0,4,15,0,0,0,5,3,0,0,41,0,0,0,1,2,32,1,144],[0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,1,4,26,0,0,0,4,1,32,0,108],[0,0,2,211,0,0,129,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,246,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,240,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,215,2,0,0,65,0,0,0,215,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,0,247,1,16,1,199,0,0,3,90,0,1,4,48,0,0,0,96,7,16,0,57],[0,0,0,64,0,112,4,63,0,0,0,237,2,0,0,65,0,0,0,0,0,39,4,53,0,0,0,100,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,132,3,16,0,57,0,0,0,0,2,1,4,51],[0,0,0,0,0,35,4,53,0,0,0,164,3,16,0,57,0,0,0,0,4,2,0,75,0,0,2,68,0,0,97,61],[0,0,0,0,4,0,0,25,0,0,0,0,5,52,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,20,0,25],[0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,2,61,0,0,65,61],[0,0,0,0,1,50,0,25,0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,32,2,0,0,138],[0,0,0,0,1,33,1,111,0,0,0,215,2,0,0,65,0,0,0,215,3,112,0,156,0,0,0,0,3,2,0,25],[0,0,0,0,3,7,64,25,0,0,0,64,3,48,2,16,0,0,0,68,1,16,0,57,0,0,0,215,4,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20],[0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159],[0,0,128,8,2,0,0,57,0,3,0,0,0,7,0,29,3,88,3,78,0,0,4,15,0,0,0,3,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,215,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,2,110,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,2,102,0,0,65,61,0,0,0,0,7,5,0,75,0,0,2,125,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,2,159,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,2,16,1,143,0,0,0,0,1,162,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,0,233,4,16,0,156,0,0,0,5,5,0,0,41,0,0,0,4,4,0,0,41],[0,0,1,221,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,221,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,2,48,0,140,0,0,3,10,0,0,65,61,0,0,0,0,0,65,4,53,0,0,0,215,2,0,0,65],[0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,215,4,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159],[0,0,0,244,1,16,1,199,0,0,0,229,6,80,1,151,0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57],[0,0,0,0,5,0,4,17,0,0,0,249,4,0,0,65,0,0,3,5,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,2,172,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,2,164,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,2,187,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,215,1,0,0,65],[0,0,0,215,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,3,90,0,1,4,48,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61],[0,0,0,0,0,49,4,53,0,0,0,215,2,0,0,65,0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,215,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,0,244,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,2,3,0,0,57,0,0,0,254,4,0,0,65,0,0,3,5,0,0,1,61,0,2,0,0,0,2,0,29],[0,0,0,0,0,48,4,53,0,0,0,32,0,0,4,63,0,0,0,215,3,0,0,65,0,0,0,0,1,0,4,20],[0,0,0,215,2,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,235,1,16,1,199],[0,0,128,16,2,0,0,57,3,88,3,83,0,0,4,15,0,0,0,3,3,0,0,41,0,0,0,1,2,32,1,144],[0,0,3,10,0,0,97,61,0,0,0,2,4,0,0,41,0,0,0,4,2,64,0,106,0,0,0,0,1,1,4,59],[0,0,0,0,0,33,4,27,0,0,0,0,0,48,4,53,0,0,0,0,1,0,4,20,0,0,0,215,2,16,0,156],[0,0,0,215,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57],[3,88,3,83,0,0,4,15,0,0,0,3,6,0,0,41,0,0,0,5,5,0,0,41,0,0,0,1,2,32,1,144],[0,0,3,10,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,1,4,26,0,0,0,4,3,0,0,41],[0,0,0,0,2,50,0,25,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61,0,0,0,0,0,49,4,53],[0,0,0,215,2,0,0,65,0,0,0,0,3,0,4,20,0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,215,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,0,244,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57],[0,0,0,245,4,0,0,65,3,88,3,78,0,0,4,15,0,0,0,1,1,32,1,144,0,0,3,10,0,0,97,61],[0,0,0,0,1,0,0,25,0,0,3,89,0,1,4,46,0,0,0,0,1,0,0,25,0,0,3,90,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,3,25,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,3,17,0,0,65,61,0,0,0,0,6,4,0,75,0,0,3,40,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,2,187,0,0,1,61,0,0,0,0,3,1,4,51,0,0,0,0,2,50,4,54,0,0,0,0,4,3,0,75],[0,0,3,53,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,36,0,25,0,0,0,32,4,64,0,57],[0,0,0,0,6,20,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53,0,0,0,0,5,52,0,75],[0,0,3,46,0,0,65,61,0,0,0,0,1,35,0,25,0,0,0,0,0,1,4,53,0,0,0,31,1,48,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,1,49,1,111,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,45],[0,0,0,215,2,0,0,65,0,0,0,215,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,0,3,0,4,20],[0,0,0,215,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,64,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,235,1,16,1,199,0,0,128,16,2,0,0,57,3,88,3,83,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,3,76,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,3,90,0,1,4,48,0,0,3,81,0,33,4,33,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,3,86,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,3,88,0,0,4,50,0,0,3,89,0,1,4,46,0,0,3,90,0,1,4,48,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,207,248,216],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,188,62,175],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,188,62,176],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,149,216,155,65],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,199,247,8],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,207,248,217],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,153,82,252],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,60,229,102],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,60,229,103],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,193,15,25],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,253,222,3],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,22,13,221],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[69,84,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[108,9,96,249,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[98,248,75,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[196,5,254,137,88,65,11,186,240,199,59,122,12,62,32,133,158,134,202,22,138,76,155,13,239,156,84,210,85,90,48,107],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[79,110,108,121,32,115,121,115,116,101,109,32,99,111,110,116,114,97,99,116,115,32,119,105,116,104,32,115,112,101,99,105],[97,108,32,97,99,99,101,115,115,32,99,97,110,32,99,97,108,108,32,116,104,105,115,32,109,101,116,104,111,100,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[221,242,82,173,27,226,200,155,105,194,176,104,252,55,141,170,149,43,167,241,99,196,161,22,40,245,90,77,245,35,179,239],[84,114,97,110,115,102,101,114,32,97,109,111,117,110,116,32,101,120,99,101,101,100,115,32,98,97,108,97,110,99,101,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,160],[39,23,234,214,185,32,13,210,53,170,212,104,201,128,158,164,0,254,51,172,105,181,191,170,109,62,144,252,146,43,99,152],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[15,103,152,165,96,121,58,84,195,188,254,134,169,60,222,30,115,8,125,148,76,14,162,5,68,19,125,65,33,57,104,133],[69,116,104,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[138,45,232,35,156,84,136,62,74,211,18,128,185,183,6,203,181,237,138,115,51,209,123,80,172,154,86,215,37,44,38,96]],"0x0000000000000000000000000000000000008004":[[0,1,0,0,0,0,0,2,0,8,0,0,0,0,0,2,0,0,0,0,0,1,3,85,0,0,0,128,3,0,0,57],[0,0,0,64,0,48,4,63,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,95,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,0,32,0,0,193,61,0,0,0,4,2,48,0,140,0,0,1,24,0,0,65,61],[0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112,0,0,0,97,4,32,0,156,0,0,0,40,0,0,97,61],[0,0,0,98,4,32,0,156,0,0,0,127,0,0,97,61,0,0,0,99,2,32,0,156,0,0,1,24,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,24,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,1,24,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,0,123,1,0,0,65,0,0,1,121,0,1,4,46],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,1,24,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,96,1,0,0,65,0,0,1,121,0,1,4,46],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,24,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,64,2,32,0,140,0,0,1,24,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,4,2,4,59],[0,0,0,0,2,4,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57,0,2,0,0,0,4,0,29],[0,0,0,0,2,36,0,75,0,0,1,24,0,0,193,61,0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,100,4,32,0,156,0,0,1,24,0,0,33,61,0,0,0,35,4,32,0,57,0,0,0,101,5,0,0,65],[0,0,0,0,6,52,0,75,0,0,0,0,6,0,0,25,0,0,0,0,6,5,128,25,0,0,0,101,4,64,1,151],[0,0,0,0,7,4,0,75,0,0,0,0,5,0,128,25,0,0,0,101,4,64,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,4,5,0,75,0,0,1,24,0,0,193,61,0,0,0,4,4,32,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,4,4,4,59,0,8,0,0,0,4,0,29,0,0,0,100,4,64,0,156,0,0,1,24,0,0,33,61],[0,7,0,36,0,32,0,61,0,0,0,8,2,0,0,41,0,0,0,5,2,32,2,16,0,0,0,7,2,32,0,41],[0,0,0,0,2,50,0,75,0,0,1,24,0,0,33,61,0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140],[0,0,0,192,0,0,193,61,0,0,0,8,2,0,0,107,0,0,0,190,0,0,97,61,0,0,0,2,2,0,0,107],[0,0,0,200,0,0,193,61,0,5,0,1,0,0,0,61,0,4,128,13,0,0,0,61,0,3,0,3,0,0,0,61],[0,0,0,0,4,0,0,25,0,0,0,97,0,0,1,61,0,0,0,1,4,64,0,57,0,0,0,8,2,64,0,108],[0,0,0,190,0,0,129,61,0,0,0,5,2,64,2,16,0,0,0,7,2,32,0,41,0,0,0,0,2,33,3,79],[0,0,0,0,5,2,4,59,0,0,0,0,2,5,4,26,0,0,0,0,2,2,0,75,0,0,0,94,0,0,193,61],[0,0,0,105,1,80,1,151,0,0,0,106,1,16,0,156,0,0,1,26,0,0,193,61,0,6,0,0,0,4,0,29],[0,0,0,107,1,80,1,152,0,0,1,47,0,0,97,61,0,0,0,5,1,0,0,41,0,0,0,0,0,21,4,27],[0,0,0,0,1,0,4,20,0,0,0,95,2,16,0,156,0,0,0,95,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,0,113,1,16,1,199,0,0,0,4,2,0,0,41,0,0,0,3,3,0,0,41,0,0,0,114,4,0,0,65],[0,0,0,0,6,0,0,25,1,120,1,110,0,0,4,15,0,0,0,0,1,0,3,103,0,0,0,1,2,32,1,144],[0,0,0,6,4,0,0,41,0,0,0,94,0,0,193,61,0,0,1,24,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,1,24,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140],[0,0,1,24,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,5,1,4,59,0,0,0,0,1,0,4,17],[0,0,128,14,1,16,0,140,0,0,0,153,0,0,193,61,0,0,0,0,1,5,4,26,0,0,0,0,1,1,0,75],[0,0,0,190,0,0,193,61,0,0,0,105,1,80,1,151,0,0,0,106,1,16,0,156,0,0,0,163,0,0,193,61],[0,0,0,107,1,80,1,152,0,0,0,175,0,0,193,61,0,0,0,102,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,164,0,16,4,63,0,0,0,119,1,0,0,65],[0,0,0,160,0,0,1,61,0,0,0,102,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,121,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,104,1,0,0,65,0,0,1,122,0,1,4,48,0,0,0,102,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,34,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,117,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,116,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,0,122,1,0,0,65,0,0,1,122,0,1,4,48,0,0,0,1,1,0,0,57],[0,0,0,0,0,21,4,27,0,0,0,95,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,95,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,113,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,3,3,0,0,57,0,0,0,114,4,0,0,65,0,0,0,0,6,0,0,25,1,120,1,110,0,0,4,15],[0,0,0,1,1,32,1,144,0,0,1,24,0,0,97,61,0,0,0,0,1,0,0,25,0,0,1,121,0,1,4,46],[0,0,0,102,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,103,1,0,0,65,0,0,0,160,0,0,1,61],[0,5,128,8,0,0,0,61,0,1,128,2,0,0,0,61,0,0,0,0,4,0,0,25,0,0,0,207,0,0,1,61],[0,0,0,1,4,64,0,57,0,0,0,8,2,64,0,108,0,0,0,190,0,0,129,61,0,0,0,5,2,64,2,16],[0,0,0,7,2,32,0,41,0,0,0,0,2,33,3,79,0,0,0,0,3,2,4,59,0,0,0,0,2,3,4,26],[0,0,0,0,2,2,0,75,0,0,0,204,0,0,193,61,0,0,0,105,1,48,1,151,0,0,0,106,1,16,0,156],[0,0,1,26,0,0,193,61,0,4,0,0,0,4,0,29,0,6,0,0,0,3,0,29,0,0,0,107,1,48,1,152],[0,0,1,47,0,0,97,61,0,0,0,108,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,5,1,0,0,41],[0,0,0,4,0,16,4,67,0,0,0,0,1,0,4,20,0,0,0,95,2,16,0,156,0,0,0,95,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,0,109,1,16,1,199,0,0,0,1,2,0,0,41,1,120,1,115,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,1,64,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,0,6,2,0,0,41,0,0,1,24,0,0,97,61,0,0,0,64,4,0,4,61,0,0,0,110,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,0,0,33,4,53,0,0,0,0,1,0,4,20],[0,0,0,95,2,16,0,156,0,0,0,95,3,0,0,65,0,0,0,0,1,3,128,25,0,0,0,95,2,64,0,156],[0,3,0,0,0,4,0,29,0,0,0,0,2,3,0,25,0,0,0,0,2,4,64,25,0,0,0,64,2,32,2,16],[0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,111,1,16,1,199,0,0,0,5,2,0,0,41],[1,120,1,110,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,65,0,0,97,61,0,0,0,3,2,0,0,41],[0,0,0,112,1,32,0,156,0,0,1,103,0,0,129,61,0,0,0,64,0,32,4,63,0,0,0,1,1,0,0,57],[0,0,0,6,5,0,0,41,0,0,0,0,0,21,4,27,0,0,0,0,1,0,4,20,0,0,0,95,2,16,0,156],[0,0,0,95,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,113,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,3,3,0,0,57,0,0,0,114,4,0,0,65,0,0,0,2,6,0,0,41,1,120,1,110,0,0,4,15],[0,0,0,0,1,0,3,103,0,0,0,1,2,32,1,144,0,0,0,4,4,0,0,41,0,0,0,204,0,0,193,61],[0,0,0,0,1,0,0,25,0,0,1,122,0,1,4,48,0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57],[0,0,0,116,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,0,117,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,34,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,102,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,95,2,0,0,65,0,0,0,95,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,0,118,1,16,1,199,0,0,1,122,0,1,4,48,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,0,119,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,102,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,4,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,95,2,0,0,65,0,0,0,95,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,120,1,16,1,199,0,0,1,122,0,1,4,48],[0,0,0,0,0,1,4,47,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,0,95,3,48,1,151,0,0,0,5,5,48,2,114,0,0,1,81,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,1,73,0,0,65,61,0,0,0,0,6,4,0,75,0,0,1,96,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,0,95,1,0,0,65,0,0,0,95,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,1,122,0,1,4,48,0,0,0,115,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,0,111,1,0,0,65],[0,0,1,122,0,1,4,48,0,0,0,0,0,1,4,47,0,0,1,113,0,33,4,33,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,1,118,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,1,120,0,0,4,50,0,0,1,121,0,1,4,46,0,0,1,122,0,1,4,48,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,229,22,118,30],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,121,196,249,41],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,99,20,240],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[57,179,76,110,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[201,71,34,255,19,234,207,83,84,124,71,65,218,181,34,131,83,160,89,56,255,205,213,212,162,213,51,174,14,97,130,135],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,99,111,114,114,101,99,116,108,121,32,102,111,114,109,97,116,116,101,100,32,98,121,116,101,99,111,100,101,72,97],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[67,111,100,101,32,108,101,110,103,116,104,32,105,110,32,119,111,114,100,115,32,109,117,115,116,32,98,101,32,111,100,100],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,99,111,109,112,114,101,115,115,111,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[19,244,124,140,251,27,40,215,67,122,206,132,217,200,125,100,205,240,125,135,58,151,188,173,230,233,239,192,213,110,224,239]],"0x0000000000000000000000000000000000008006":[[0,2,0,0,0,0,0,2,0,11,0,0,0,0,0,2,0,0,0,0,3,2,0,25,0,1,0,0,0,1,3,85],[0,0,0,0,2,1,0,25,0,0,0,96,2,32,2,112,0,0,4,244,0,32,1,157,0,0,0,128,4,0,0,57],[0,0,0,64,0,64,4,63,0,0,4,244,2,32,1,151,0,0,0,1,4,48,1,144,0,0,0,134,0,0,193,61],[0,0,0,4,4,32,0,140,0,0,7,102,0,0,65,61,0,0,0,0,4,1,4,59,0,0,0,224,4,64,2,112],[0,0,4,246,5,64,0,156,0,0,0,142,0,0,161,61,0,0,4,247,5,64,0,156,0,0,0,207,0,0,161,61],[0,0,4,248,5,64,0,156,0,0,0,0,5,0,4,16,0,11,0,0,0,5,0,29,0,0,1,71,0,0,33,61],[0,0,4,251,5,64,0,156,0,0,1,180,0,0,97,61,0,0,4,252,4,64,0,156,0,0,7,102,0,0,193,61],[0,0,0,0,4,0,4,22,0,0,0,0,4,4,0,75,0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138],[0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,11,0,0,0,1,0,29,0,0,0,1,1,16,0,140,0,0,7,102,0,0,33,61,0,0,0,0,2,0,4,17],[0,0,0,2,1,48,1,144,0,0,0,44,0,0,193,61,0,0,255,255,1,32,0,140,0,0,3,170,0,0,33,61],[0,10,0,0,0,2,0,29,0,0,0,0,0,32,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,32,2,64,0,156,0,0,3,211,0,0,33,61],[0,0,0,0,1,1,4,59,0,0,0,64,2,64,0,57,0,0,0,64,0,32,4,63,0,0,0,0,1,1,4,26],[0,0,0,255,2,16,1,143,0,0,0,1,3,32,0,140,0,0,4,25,0,0,33,61,0,0,0,0,3,36,4,54],[0,0,0,8,1,16,2,112,0,0,0,255,1,16,1,143,0,0,0,1,2,16,0,140,0,0,4,25,0,0,33,61],[0,9,0,0,0,4,0,29,0,0,0,0,0,19,4,53,0,0,0,11,2,0,0,41,0,0,0,1,2,32,0,140],[0,0,6,94,0,0,193,61,0,0,0,0,1,1,0,75,0,0,6,94,0,0,193,61,0,0,0,1,1,0,0,57],[0,11,0,0,0,3,0,29,0,8,0,0,0,1,0,29,0,0,0,0,0,19,4,53,0,0,0,10,1,0,0,41],[0,0,5,9,1,16,1,151,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,7,102,0,0,97,61,0,0,0,9,2,0,0,41,0,0,0,0,2,2,4,51,0,0,0,1,3,32,0,140],[0,0,0,11,5,0,0,41,0,0,4,25,0,0,33,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,0,3,5,4,51,0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61,0,0,5,16,4,0,0,65],[0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143,0,0,0,0,2,35,1,159],[0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61,0,0,0,8,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,2,0,0,65,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,5,49,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57],[0,0,5,50,4,0,0,65,0,0,0,201,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,7,102,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,4,245,1,0,0,65,0,0,19,202,0,1,4,46,0,0,5,0,5,64,0,156,0,0,1,35,0,0,33,61],[0,0,5,4,5,64,0,156,0,0,2,240,0,0,97,61,0,0,5,5,5,64,0,156,0,0,3,125,0,0,97,61],[0,0,5,6,4,64,0,156,0,0,7,102,0,0,193,61,0,0,0,0,4,0,4,22,0,0,0,0,4,4,0,75],[0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138,0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,11,0,0,0,1,0,29,0,0,0,1,1,16,0,140],[0,0,7,102,0,0,33,61,0,0,0,0,2,0,4,17,0,0,0,2,1,48,1,144,0,0,0,166,0,0,193,61],[0,0,255,255,1,32,0,140,0,0,3,170,0,0,33,61,0,10,0,0,0,2,0,29,0,0,0,0,0,32,4,53],[0,0,0,32,0,0,4,63,0,0,4,244,3,0,0,65,0,0,0,0,1,0,4,20,0,0,4,244,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,2,1,4,26,0,0,1,0,3,0,0,138,0,0,0,0,2,50,1,111,0,0,0,11,3,0,0,41],[0,0,0,0,2,50,1,159,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61,0,0,0,0,0,49,4,53],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,4,244,4,0,0,65,0,0,0,0,2,4,128,25],[0,0,4,244,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,49,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,2,3,0,0,57],[0,0,5,67,4,0,0,65,0,0,0,10,5,0,0,41,19,201,19,180,0,0,4,15,0,0,0,1,1,32,1,144],[0,0,7,102,0,0,97,61,0,0,0,0,1,0,0,25,0,0,19,202,0,1,4,46,0,0,4,253,5,64,0,156],[0,0,2,81,0,0,97,61,0,0,4,254,3,64,0,156,0,0,2,188,0,0,97,61,0,0,4,255,3,64,0,156],[0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138,0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,2,1,4,59,0,0,0,0,1,0,4,17,0,0,128,7,1,16,0,140],[0,0,3,215,0,0,193,61,0,0,5,13,1,0,0,65,0,0,0,128,0,16,4,63,0,11,0,0,0,2,0,29],[0,0,0,132,0,32,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,4,2,0,0,57],[19,201,19,185,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,0,251,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,0,243,0,0,65,61,0,0,0,0,7,5,0,75],[0,0,1,10,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16],[0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47],[0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207],[0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,3,225,0,0,97,61],[0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,128,1,32,1,191,0,0,0,64,0,16,4,63],[0,0,0,32,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,128,3,0,4,61,0,0,0,0,3,3,0,75],[0,0,4,119,0,0,193,61,0,0,5,10,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,132,3,32,1,191],[0,0,0,32,4,0,0,57,0,0,0,0,0,67,4,53,0,0,0,196,3,32,0,57,0,0,5,41,4,0,0,65],[0,0,0,0,0,67,4,53,0,0,0,164,2,32,0,57,0,0,0,26,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,64,1,16,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,5,1,5,64,0,156],[0,0,3,7,0,0,97,61,0,0,5,2,3,64,0,156,0,0,3,182,0,0,97,61,0,0,5,3,3,64,0,156],[0,0,7,102,0,0,193,61,0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61],[0,0,0,4,3,32,0,138,0,0,0,128,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,4,3,16,3,112],[0,0,0,0,3,3,4,59,0,11,0,0,0,3,0,29,0,0,5,9,3,48,0,156,0,0,7,102,0,0,33,61],[0,0,0,100,1,16,3,112,0,0,0,0,1,1,4,59,0,0,5,7,3,16,0,156,0,0,7,102,0,0,33,61],[0,0,0,4,1,16,0,57,19,201,10,44,0,0,4,15,0,0,0,1,4,0,3,103,0,0,0,68,3,64,3,112],[0,0,0,0,3,3,4,59,0,0,0,36,4,64,3,112,0,0,0,0,4,4,4,59,0,0,0,0,5,1,0,25],[0,0,0,0,6,2,0,25,0,0,0,11,1,0,0,41,0,0,0,0,2,4,0,25,0,0,0,0,4,5,0,25],[0,0,0,0,5,6,0,25,19,201,10,70,0,0,4,15,0,0,2,254,0,0,1,61,0,0,4,249,5,64,0,156],[0,0,1,224,0,0,97,61,0,0,4,250,3,64,0,156,0,0,7,102,0,0,193,61,0,0,0,4,3,32,0,138],[0,0,0,64,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,4,3,16,3,112,0,0,0,0,3,3,4,59],[0,10,0,0,0,3,0,29,0,0,5,7,3,48,0,156,0,0,7,102,0,0,33,61,0,0,0,10,4,32,0,106],[0,0,5,8,2,0,0,65,0,0,0,164,3,64,0,140,0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25],[0,9,0,0,0,4,0,29,0,0,5,8,4,64,1,151,0,0,0,0,5,4,0,75,0,0,0,0,2,0,160,25],[0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75,0,0,7,102,0,0,193,61],[0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59,0,8,0,0,0,2,0,29,0,0,5,9,2,32,0,156],[0,0,7,102,0,0,33,61,0,0,0,0,2,0,4,17,0,0,0,11,2,32,0,108,0,0,4,43,0,0,193,61],[0,0,0,10,2,0,0,41,0,7,0,4,0,32,0,61,0,0,0,7,1,16,3,96,0,0,0,0,2,1,4,59],[0,0,5,13,1,0,0,65,0,0,0,128,0,16,4,63,0,6,0,0,0,2,0,29,0,0,0,132,0,32,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,4,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,1,138,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,1,130,0,0,65,61,0,0,0,0,7,5,0,75,0,0,1,153,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,5,174,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,2,16,1,191,0,5,0,0,0,2,0,29,0,0,0,64,0,32,4,63],[0,0,0,32,2,48,0,140,0,0,7,102,0,0,65,61,0,0,0,128,2,0,4,61,0,0,0,0,2,2,0,75],[0,0,6,118,0,0,193,61,0,0,5,10,2,0,0,65,0,0,0,5,4,0,0,41,0,0,0,0,0,36,4,53],[0,0,0,132,2,16,1,191,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,196,2,16,0,57],[0,0,5,41,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,164,1,16,0,57,0,0,0,26,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,64,1,64,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48],[0,0,0,4,3,32,0,138,0,0,0,32,3,48,0,140,0,0,7,102,0,0,65,61,0,0,0,4,3,16,3,112],[0,0,0,0,3,3,4,59,0,5,0,0,0,3,0,29,0,0,5,7,3,48,0,156,0,0,7,102,0,0,33,61],[0,0,0,5,3,0,0,41,0,0,0,35,3,48,0,57,0,0,5,8,4,0,0,65,0,0,0,0,5,35,0,75],[0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25,0,0,5,8,3,48,1,151,0,0,0,0,6,3,0,75],[0,0,0,0,4,0,128,25,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75],[0,0,7,102,0,0,193,61,0,0,0,5,3,0,0,41,0,0,0,4,3,48,0,57,0,0,0,0,3,49,3,79],[0,0,0,0,13,3,4,59,0,0,5,7,3,208,0,156,0,0,7,102,0,0,33,61,0,0,0,5,3,0,0,41],[0,0,0,36,14,48,0,57,0,0,0,5,3,208,2,16,0,0,0,0,3,227,0,25,0,0,0,0,3,35,0,75],[0,0,7,102,0,0,33,61,0,0,0,9,4,0,0,138,0,0,0,0,3,0,4,17,0,0,0,0,4,67,1,111],[0,0,128,7,4,64,0,140,0,0,4,31,0,0,193,61,0,0,0,0,4,13,0,75,0,0,4,180,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,0,205,0,0,97,61,0,0,6,22,0,0,1,61],[0,0,0,4,4,32,0,138,0,0,0,128,4,64,0,140,0,0,7,102,0,0,65,61,0,0,0,36,4,16,3,112],[0,0,0,0,4,4,4,59,0,11,0,0,0,4,0,29,0,0,0,68,4,16,3,112,0,0,0,0,4,4,4,59],[0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61,0,0,0,35,5,64,0,57,0,0,5,8,6,0,0,65],[0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25,0,0,5,8,5,80,1,151],[0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25,0,0,5,8,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61,0,0,0,4,5,64,0,57,0,0,0,0,5,81,3,79],[0,0,0,0,5,5,4,59,0,10,0,0,0,5,0,29,0,0,5,7,5,80,0,156,0,0,7,102,0,0,33,61],[0,0,0,36,5,64,0,57,0,9,0,0,0,5,0,29,0,0,0,10,4,80,0,41,0,0,0,0,2,36,0,75],[0,0,7,102,0,0,33,61,0,0,0,100,1,16,3,112,0,0,0,0,1,1,4,59,0,8,0,0,0,1,0,29],[0,0,0,1,1,16,0,140,0,0,7,102,0,0,33,61,0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112],[0,0,2,13,0,0,193,61,0,0,0,0,1,0,4,17,0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,64,57,0,0,0,0,1,1,0,75,0,0,3,170,0,0,97,61,0,0,5,43,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17,0,7,0,0,0,1,0,29,0,0,0,132,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,2,46,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,2,38,0,0,65,61,0,0,0,0,7,5,0,75,0,0,2,61,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,6,36,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,7,102,0,0,65,61,0,0,0,128,2,0,4,61,0,0,0,7,1,0,0,41,19,201,11,13,0,0,4,15],[0,0,0,0,2,1,0,25,0,7,0,0,0,2,0,29,0,0,0,11,1,0,0,41,0,0,0,8,3,0,0,41],[0,0,0,9,4,0,0,41,0,0,0,10,5,0,0,41,19,201,15,118,0,0,4,15,0,0,0,7,1,0,0,41],[0,0,2,254,0,0,1,61,0,0,0,4,4,32,0,138,0,0,0,96,4,64,0,140,0,0,7,102,0,0,65,61],[0,0,0,36,4,16,3,112,0,0,0,0,4,4,4,59,0,11,0,0,0,4,0,29,0,0,0,68,4,16,3,112],[0,0,0,0,4,4,4,59,0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61,0,0,0,35,5,64,0,57],[0,0,5,8,6,0,0,65,0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25],[0,0,5,8,5,80,1,151,0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25,0,0,5,8,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61,0,0,0,4,5,64,0,57],[0,0,0,0,1,81,3,79,0,0,0,0,1,1,4,59,0,10,0,0,0,1,0,29,0,0,5,7,1,16,0,156],[0,0,7,102,0,0,33,61,0,0,0,36,4,64,0,57,0,9,0,0,0,4,0,29,0,0,0,10,1,64,0,41],[0,0,0,0,1,33,0,75,0,0,7,102,0,0,33,61,0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112],[0,0,2,121,0,0,193,61,0,0,0,0,1,0,4,17,0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,64,57,0,0,0,0,1,1,0,75,0,0,3,170,0,0,97,61,0,0,5,43,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17,0,8,0,0,0,1,0,29,0,0,0,132,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,2,154,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,2,146,0,0,65,61,0,0,0,0,7,5,0,75,0,0,2,169,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,5,203,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,7,102,0,0,65,61,0,0,0,128,2,0,4,61,0,0,0,8,1,0,0,41,19,201,11,13,0,0,4,15],[0,0,0,0,2,1,0,25,0,8,0,0,0,2,0,29,0,0,0,11,1,0,0,41,0,0,0,9,3,0,0,41],[0,0,0,10,4,0,0,41,19,201,11,57,0,0,4,15,0,0,0,8,1,0,0,41,0,0,2,254,0,0,1,61],[0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138],[0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,11,0,0,0,1,0,29,0,0,5,9,1,16,0,156,0,0,7,102,0,0,33,61,0,0,0,11,1,0,0,41],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199],[0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,5,32,3,32,0,156,0,0,3,211,0,0,33,61,0,0,0,0,1,1,4,59],[0,0,0,64,3,32,0,57,0,0,0,64,0,48,4,63,0,0,0,0,1,1,4,26,0,0,0,255,3,16,1,143],[0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61,0,0,0,0,3,50,4,54,0,0,0,8,1,16,2,112],[0,0,0,255,1,16,1,143,0,0,0,1,4,16,0,140,0,0,4,25,0,0,33,61,0,0,0,0,0,19,4,53],[0,0,0,0,2,2,4,51,0,0,0,1,1,32,0,140,0,0,4,25,0,0,33,61,0,0,0,1,1,0,0,57],[0,0,0,0,2,2,0,75,0,0,2,255,0,0,193,61,0,0,0,11,1,0,0,41,0,0,5,63,1,16,1,152],[0,0,0,0,1,0,0,25,0,0,7,33,0,0,193,61,0,0,0,1,1,16,1,143,0,0,2,255,0,0,1,61],[0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138],[0,0,0,64,2,32,0,140,0,0,7,102,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,3,2,4,59],[0,0,5,9,2,48,0,156,0,0,7,102,0,0,33,61,0,0,0,36,1,16,3,112,0,0,0,0,2,1,4,59],[0,0,0,0,1,3,0,25,19,201,11,13,0,0,4,15,0,0,5,9,1,16,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,5,44,1,16,1,199,0,0,19,202,0,1,4,46,0,0,0,4,4,32,0,138],[0,0,0,128,4,64,0,140,0,0,7,102,0,0,65,61,0,0,0,36,4,16,3,112,0,0,0,0,4,4,4,59],[0,11,0,0,0,4,0,29,0,0,0,4,4,16,3,112,0,0,0,0,4,4,4,59,0,10,0,0,0,4,0,29],[0,0,0,68,4,16,3,112,0,0,0,0,4,4,4,59,0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61],[0,0,0,35,5,64,0,57,0,0,5,8,6,0,0,65,0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,5,8,5,80,1,151,0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25],[0,0,5,8,5,80,0,156,0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61],[0,0,0,4,5,64,0,57,0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,9,0,0,0,5,0,29],[0,0,5,7,5,80,0,156,0,0,7,102,0,0,33,61,0,0,0,36,5,64,0,57,0,8,0,0,0,5,0,29],[0,0,0,9,4,80,0,41,0,0,0,0,2,36,0,75,0,0,7,102,0,0,33,61,0,0,0,100,1,16,3,112],[0,0,0,0,1,1,4,59,0,7,0,0,0,1,0,29,0,0,0,1,1,16,0,140,0,0,7,102,0,0,33,61],[0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112,0,0,3,55,0,0,193,61,0,0,0,0,1,0,4,17],[0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57,0,0,0,0,1,1,0,75],[0,0,3,170,0,0,97,61,0,0,5,43,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17],[0,6,0,0,0,1,0,29,0,0,0,132,0,16,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199],[0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,3,88,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57],[0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,3,80,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,3,103,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,6,65,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191],[0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140,0,0,7,102,0,0,65,61,0,0,0,6,1,0,0,41],[0,0,0,11,2,0,0,41,0,0,0,10,3,0,0,41,0,0,0,8,4,0,0,41,0,0,0,9,5,0,0,41],[19,201,10,70,0,0,4,15,0,0,0,0,2,1,0,25,0,10,0,0,0,2,0,29,0,0,0,11,1,0,0,41],[0,0,0,7,3,0,0,41,0,0,0,8,4,0,0,41,0,0,0,9,5,0,0,41,19,201,15,118,0,0,4,15],[0,0,4,117,0,0,1,61,0,0,0,4,4,32,0,138,0,0,0,96,4,64,0,140,0,0,7,102,0,0,65,61],[0,0,0,36,4,16,3,112,0,0,0,0,4,4,4,59,0,11,0,0,0,4,0,29,0,0,0,4,4,16,3,112],[0,0,0,0,4,4,4,59,0,10,0,0,0,4,0,29,0,0,0,68,4,16,3,112,0,0,0,0,4,4,4,59],[0,0,5,7,5,64,0,156,0,0,7,102,0,0,33,61,0,0,0,35,5,64,0,57,0,0,5,8,6,0,0,65],[0,0,0,0,7,37,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25,0,0,5,8,5,80,1,151],[0,0,0,0,8,5,0,75,0,0,0,0,6,0,128,25,0,0,5,8,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,7,102,0,0,193,61,0,0,0,4,5,64,0,57,0,0,0,0,1,81,3,79],[0,0,0,0,1,1,4,59,0,9,0,0,0,1,0,29,0,0,5,7,1,16,0,156,0,0,7,102,0,0,33,61],[0,0,0,36,4,64,0,57,0,8,0,0,0,4,0,29,0,0,0,9,1,64,0,41,0,0,0,0,1,33,0,75],[0,0,7,102,0,0,33,61,0,0,0,2,1,48,1,144,0,0,0,1,1,16,2,112,0,0,3,168,0,0,193,61],[0,0,0,0,1,0,4,17,0,0,5,42,1,16,0,156,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57],[0,0,0,0,1,1,0,75,0,0,4,51,0,0,193,61,0,0,5,10,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,5,68,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,69,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,5,70,1,0,0,65,0,0,19,203,0,1,4,48,0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75],[0,0,7,102,0,0,193,61,0,0,0,4,2,32,0,138,0,0,0,32,2,32,0,140,0,0,7,102,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,5,9,2,16,0,156,0,0,7,102,0,0,33,61],[0,0,0,192,2,0,0,57,0,0,0,64,0,32,4,63,0,0,0,128,0,0,4,63,0,0,0,160,0,0,4,63],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199],[0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61],[0,0,0,64,2,0,4,61,0,0,5,65,3,32,0,156,0,0,4,4,0,0,65,61,0,0,5,58,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,4,28,0,0,1,61,0,0,5,10,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,62,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,12,1,0,0,65],[0,0,19,203,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,3,238,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,3,230,0,0,65,61,0,0,0,0,6,4,0,75,0,0,3,253,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,4,244,1,0,0,65,0,0,4,244,4,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,19,203,0,1,4,48],[0,0,0,0,1,1,4,59,0,0,0,64,3,32,0,57,0,0,0,64,0,48,4,63,0,0,0,0,3,1,4,26],[0,0,0,255,1,48,1,143,0,0,0,2,4,16,0,140,0,0,4,25,0,0,129,61,0,0,0,0,1,18,4,54],[0,0,0,8,3,48,2,112,0,0,0,255,3,48,1,143,0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61],[0,0,0,0,0,49,4,53,0,0,0,0,3,2,4,51,0,0,0,1,2,48,0,140,0,0,4,25,0,0,33,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,50,4,54,0,0,0,0,1,1,4,51,0,0,0,1,4,16,0,140],[0,0,7,26,0,0,161,61,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,33,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48,0,0,5,10,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,65,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,51,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,52,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,5,53,1,0,0,65,0,0,6,33,0,0,1,61,0,0,5,10,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,21,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,5,11,1,0,0,65,0,0,3,222,0,0,1,61,0,0,5,43,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,0,1,0,4,17,0,7,0,0,0,1,0,29,0,0,0,132,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,14,1,16,1,199,0,0,128,3,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,4,82,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,4,74,0,0,65,61,0,0,0,0,7,5,0,75,0,0,4,97,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,5,232,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,128,1,16,1,191,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140],[0,0,7,102,0,0,65,61,0,0,0,7,1,0,0,41,0,0,0,11,2,0,0,41,0,0,0,10,3,0,0,41],[0,0,0,8,4,0,0,41,0,0,0,9,5,0,0,41,19,201,10,70,0,0,4,15,0,0,0,0,2,1,0,25],[0,10,0,0,0,2,0,29,0,0,0,11,1,0,0,41,0,0,0,8,3,0,0,41,0,0,0,9,4,0,0,41],[19,201,11,57,0,0,4,15,0,0,0,10,1,0,0,41,0,0,2,254,0,0,1,61,0,0,0,0,3,0,4,22],[0,0,0,0,3,3,0,75,0,0,6,5,0,0,193,61,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,128,2,2,0,0,57,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,3,0,4,20],[0,0,4,244,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61,0,0,0,36,1,64,0,57],[0,0,0,11,2,0,0,41,0,0,0,0,0,33,4,53,0,0,5,38,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,128,16,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,10,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,7,104,0,0,97,61,0,0,0,10,1,0,0,41,0,0,5,7,1,16,0,156],[0,0,3,211,0,0,33,61,0,0,0,10,1,0,0,41,0,0,0,64,0,16,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,4,3,0,0,57,0,0,128,7,5,0,0,57],[0,0,128,16,7,0,0,57,0,0,5,40,4,0,0,65,0,0,0,11,6,0,0,41,0,0,0,202,0,0,1,61],[0,0,0,5,5,0,0,41,0,0,0,0,4,82,0,73,0,0,0,132,2,80,0,57,0,0,0,195,4,64,0,138],[0,0,5,8,6,0,0,65,0,0,0,0,7,0,0,25,0,0,0,0,5,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,8,232,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,9,72,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,6,128,25,0,0,5,8,10,64,1,151,0,0,5,8,11,128,1,151],[0,0,0,0,12,171,0,75,0,0,0,0,12,0,0,25,0,0,0,0,12,6,64,25,0,0,0,0,10,171,1,63],[0,0,5,8,10,160,0,156,0,0,0,0,12,9,192,25,0,0,0,0,9,12,0,75,0,0,7,102,0,0,193,61],[0,0,0,0,8,130,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,5,88,0,25],[0,0,0,0,8,133,0,75,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,0,1,8,128,1,144],[0,0,8,11,0,0,193,61,0,0,0,1,7,112,0,57,0,0,0,0,8,215,0,75,0,0,4,187,0,0,65,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,81,0,75,0,0,6,22,0,0,193,61,0,4,5,9,0,48,1,155],[0,0,5,8,8,0,0,65,0,0,0,0,9,0,0,25,0,8,0,0,0,13,0,29,0,7,0,0,0,14,0,29],[0,0,0,5,1,144,2,16,0,0,0,0,2,225,0,25,0,0,0,1,1,0,3,103,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,5,3,0,0,41,0,0,0,0,3,48,0,121,0,0,0,195,3,48,0,138],[0,0,0,0,4,50,0,75,0,0,0,0,4,0,0,25,0,0,0,0,4,8,128,25,0,0,5,8,3,48,1,151],[0,0,5,8,5,32,1,151,0,0,0,0,6,53,0,75,0,0,0,0,6,0,0,25,0,0,0,0,6,8,64,25],[0,0,0,0,3,53,1,63,0,0,5,8,3,48,0,156,0,0,0,0,6,4,192,25,0,0,0,0,3,6,0,75],[0,0,7,102,0,0,193,61,0,10,0,0,0,9,0,29,0,0,0,0,2,226,0,25,0,9,0,0,0,2,0,29],[0,0,0,96,2,32,0,57,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,6,0,0,0,1,0,29],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,11,1,0,0,41,0,0,0,4,0,16,4,67],[0,0,0,0,1,0,4,20,0,0,4,244,2,16,0,156,0,0,4,244,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,0,8,13,0,0,41],[0,0,0,7,14,0,0,41,0,0,5,8,8,0,0,65,0,0,0,10,9,0,0,41,0,0,0,9,11,0,0,41],[0,0,7,102,0,0,97,61,0,0,0,64,10,0,4,61,0,0,5,55,1,0,0,65,0,0,0,0,0,26,4,53],[0,0,0,4,1,160,0,57,0,0,0,64,2,0,0,57,0,0,0,0,0,33,4,53,0,0,0,1,1,0,3,103],[0,0,0,0,2,177,3,79,0,0,0,0,2,2,4,59,0,0,0,68,3,160,0,57,0,0,0,0,0,35,4,53],[0,0,0,32,2,176,0,57,0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59,0,0,5,9,4,48,0,156],[0,0,7,102,0,0,33,61,0,0,0,100,4,160,0,57,0,0,0,0,0,52,4,53,0,0,0,32,2,32,0,57],[0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59,0,0,0,0,4,3,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,192,57,0,0,0,0,4,67,0,75,0,0,7,102,0,0,193,61,0,0,0,132,4,160,0,57],[0,0,0,0,0,52,4,53,0,0,0,32,3,32,0,57,0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59],[0,0,0,164,4,160,0,57,0,0,0,0,0,52,4,53,0,0,0,64,2,32,0,57,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,0,3,0,0,49,0,0,0,0,4,179,0,73,0,0,0,31,4,64,0,138],[0,0,0,0,5,66,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,8,128,25,0,0,5,8,4,64,1,151],[0,0,5,8,6,32,1,151,0,0,0,0,7,70,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,8,64,25],[0,0,0,0,4,70,1,63,0,0,5,8,4,64,0,156,0,0,0,0,7,5,192,25,0,0,0,0,4,7,0,75],[0,0,7,102,0,0,193,61,0,0,0,0,4,178,0,25,0,0,0,0,2,65,3,79,0,0,0,0,2,2,4,59],[0,0,5,7,5,32,0,156,0,0,7,102,0,0,33,61,0,0,0,32,4,64,0,57,0,0,0,0,3,35,0,73],[0,0,0,0,5,52,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,8,32,25,0,0,5,8,3,48,1,151],[0,0,5,8,6,64,1,151,0,0,0,0,7,54,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,8,64,25],[0,0,0,0,3,54,1,63,0,0,5,8,3,48,0,156,0,0,0,0,7,5,192,25,0,0,0,0,3,7,0,75],[0,0,7,102,0,0,193,61,0,0,0,196,3,160,0,57,0,0,0,160,5,0,0,57,0,0,0,0,0,83,4,53],[0,0,0,228,3,160,0,57,0,0,0,0,0,35,4,53,0,0,0,0,3,65,3,79,0,0,1,4,1,160,0,57],[0,0,0,5,4,32,2,114,0,0,5,107,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,97,0,25,0,0,0,0,6,99,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,5,99,0,0,65,61,0,0,0,31,5,32,1,144],[0,0,5,122,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,3,67,3,79,0,0,0,0,4,65,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,4,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,3,3,4,59,0,0,1,0,5,80,0,137,0,0,0,0,3,83,2,47,0,0,0,0,3,83,1,207],[0,0,0,0,3,99,1,159,0,0,0,0,0,52,4,53,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,53],[0,0,0,36,1,160,0,57,0,0,0,4,3,0,0,41,0,0,0,0,0,49,4,53,0,0,0,0,1,0,4,20],[0,0,0,11,3,0,0,41,0,0,0,4,3,48,0,140,0,0,5,167,0,0,97,61,0,0,0,31,2,32,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,2,50,1,111,0,0,5,56,3,32,0,156,0,0,5,56,2,0,128,65],[0,0,4,244,3,160,0,156,0,0,4,244,4,0,0,65,0,9,0,0,0,10,0,29,0,0,0,0,3,4,0,25],[0,0,0,0,3,10,64,25,0,0,0,64,3,48,2,16,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159],[0,0,4,244,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,192,1,16,2,16,0,0,0,0,1,18,1,159],[0,0,5,57,1,16,0,65,0,0,0,6,3,0,0,41,0,0,0,0,2,3,0,75,0,0,5,158,0,0,97,61],[0,0,5,39,1,16,1,199,0,0,128,9,2,0,0,57,0,0,0,11,4,0,0,41,0,0,0,0,5,0,0,25],[19,201,19,180,0,0,4,15,0,0,5,160,0,0,1,61,0,0,0,11,2,0,0,41,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,8,13,0,0,41,0,0,0,7,14,0,0,41,0,0,5,8,8,0,0,65],[0,0,0,10,9,0,0,41,0,0,0,9,10,0,0,41,0,0,7,170,0,0,97,61,0,0,5,7,1,160,0,156],[0,0,3,211,0,0,33,61,0,0,0,64,0,160,4,63,0,0,0,1,9,144,0,57,0,0,0,0,1,217,0,75],[0,0,4,224,0,0,65,61,0,0,0,205,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,5,187,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,5,179,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,5,202,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,5,216,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,5,208,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,5,231,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,5,245,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,5,237,0,0,65,61,0,0,0,0,6,4,0,75,0,0,3,253,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,5,10,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,132,3,32,1,191],[0,0,0,32,4,0,0,57,0,0,0,0,0,67,4,53,0,0,0,228,3,32,0,57,0,0,5,35,4,0,0,65],[0,0,0,0,0,67,4,53,0,0,0,196,3,32,0,57,0,0,5,36,4,0,0,65,0,0,0,0,0,67,4,53],[0,0,0,164,2,32,0,57,0,0,0,56,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,64,1,16,2,16],[0,0,5,37,1,16,1,199,0,0,19,203,0,1,4,48,0,0,5,10,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,69,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,5,59,1,0,0,65,0,0,0,196,0,16,4,63,0,0,5,60,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,5,61,1,0,0,65,0,0,1,4,0,16,4,63,0,0,5,54,1,0,0,65,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,6,49,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,6,41,0,0,65,61,0,0,0,0,6,4,0,75,0,0,6,64,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,6,78,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,6,70,0,0,65,61,0,0,0,0,6,4,0,75,0,0,6,93,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,132,2,16,0,57],[0,0,5,45,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,100,2,16,0,57,0,0,5,46,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,5,47,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,67,3,0,0,57,0,0,0,0,0,50,4,53,0,0,5,10,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,4,244,2,0,0,65,0,0,4,244,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,5,48,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,192,2,16,0,57,0,0,0,64,0,32,4,63],[0,0,0,5,2,0,0,41,0,0,0,0,0,2,4,53,0,0,0,160,1,16,0,57,0,4,0,0,0,1,0,29],[0,0,0,0,0,1,4,53,0,0,0,7,1,0,0,41,0,0,0,32,1,16,0,57,0,3,0,0,0,1,0,29],[0,0,0,1,1,16,3,103,0,0,0,0,1,1,4,59,0,7,0,0,0,1,0,29,0,0,5,9,1,16,0,156],[0,0,7,102,0,0,33,61,0,0,0,7,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,7,102,0,0,97,61,0,0,0,5,2,0,0,41,0,0,0,0,2,2,4,51],[0,0,0,1,3,32,0,140,0,0,4,25,0,0,33,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,4,3,0,0,41,0,0,0,0,3,3,4,51,0,0,0,1,4,48,0,140,0,0,4,25,0,0,33,61],[0,0,5,16,4,0,0,65,0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143],[0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27,0,0,0,3,1,0,0,41,0,0,0,96,2,16,0,57],[0,0,0,1,1,0,3,103,0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59,0,0,0,9,4,0,0,41],[0,0,0,35,4,64,0,138,0,0,5,8,5,0,0,65,0,0,0,0,6,67,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,5,8,4,64,1,151,0,0,5,8,7,48,1,151,0,0,0,0,8,71,0,75],[0,0,0,0,5,0,128,25,0,0,0,0,4,71,1,63,0,0,5,8,4,64,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,4,5,0,75,0,0,7,102,0,0,193,61,0,0,0,10,3,48,0,41,0,0,0,4,4,48,0,57],[0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59,0,10,0,0,0,4,0,29,0,0,5,7,4,64,0,156],[0,0,7,102,0,0,33,61,0,0,0,10,4,0,0,41,0,0,0,0,4,64,0,121,0,0,0,36,6,48,0,57],[0,0,5,8,3,0,0,65,0,0,0,0,5,70,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,3,32,25],[0,0,5,8,4,64,1,151,0,9,0,0,0,6,0,29,0,0,5,8,6,96,1,151,0,0,0,0,7,70,0,75],[0,0,0,0,3,0,128,25,0,0,0,0,4,70,1,63,0,0,5,8,4,64,0,156,0,0,0,0,3,5,192,25],[0,0,0,0,3,3,0,75,0,0,7,102,0,0,193,61,0,0,0,64,2,32,0,138,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,0,0,2,1,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57],[0,0,0,0,2,33,0,75,0,0,7,102,0,0,193,61,0,0,0,0,2,0,4,22,0,5,0,0,0,2,0,29],[0,0,0,0,1,1,0,75,0,0,7,202,0,0,193,61,0,0,0,5,1,0,0,107,0,0,8,15,0,0,193,61],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,128,2,2,0,0,57,0,0,0,4,0,32,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,192,1,48,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,0,36,1,64,0,57,0,0,0,6,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,5,38,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,7,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,11,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,117,0,0,97,61],[0,0,0,11,1,0,0,41,0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61,0,0,0,11,1,0,0,41],[0,0,0,64,0,16,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,4,3,0,0,57,0,0,5,40,4,0,0,65,0,0,0,8,5,0,0,41,0,0,0,6,6,0,0,41],[0,0,0,7,7,0,0,41,0,0,0,202,0,0,1,61,0,0,0,0,0,19,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,5,66,1,16,1,199],[0,0,19,202,0,1,4,46,0,0,0,64,4,0,4,61,0,10,0,0,0,4,0,29,0,0,5,64,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,11,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,10,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,7,71,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,7,63,0,0,65,61,0,0,0,0,9,10,0,25],[0,0,0,0,7,5,0,75,0,0,7,87,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,105,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,7,136,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143,0,0,0,0,1,146,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,5,7,4,16,0,156],[0,0,3,211,0,0,33,61,0,0,0,1,2,32,1,144,0,0,3,211,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,32,1,48,0,140,0,0,7,165,0,0,129,61,0,0,0,0,1,0,0,25,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,7,120,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,7,112,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,7,135,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,7,149,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,7,141,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,164,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,0,1,9,4,51,0,0,0,0,1,1,0,75,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,0,0,2,238,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114],[0,0,7,186,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,7,178,0,0,65,61,0,0,0,0,6,4,0,75,0,0,7,201,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61,0,0,0,5,1,0,0,107,0,0,8,34,0,0,193,61],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,128,2,2,0,0,57,0,0,0,4,0,32,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,192,1,48,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57],[0,0,0,7,1,0,0,41,0,4,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,6,1,0,0,41],[0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57,0,3,0,0,0,2,0,29],[0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,11,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,2,0,64,0,16,2,24,0,0,0,192,1,32,2,16,0,0,0,2,1,16,1,175,0,0,5,24,1,16,1,199],[0,0,128,2,2,0,0,57,0,1,0,0,0,2,0,29,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,8,85,0,0,97,61,0,0,0,11,1,0,0,41,0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61],[0,0,0,11,1,0,0,41,0,0,0,64,0,16,4,63,0,0,0,5,1,0,0,107,0,0,8,3,0,0,97,61],[0,0,0,0,1,0,4,22,0,0,5,25,1,16,1,151,0,0,0,0,0,1,4,23,0,0,0,0,1,0,4,20],[0,0,0,9,3,0,0,41,0,0,0,10,2,48,0,42,0,0,4,244,4,48,1,151,0,0,8,11,0,0,65,61],[0,0,0,0,3,0,0,49,0,0,0,0,5,35,0,75,0,0,8,181,0,0,129,61,0,0,5,58,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,4,28,0,0,1,61,0,0,0,64,1,0,4,61],[0,0,0,100,2,16,0,57,0,0,5,35,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57],[0,0,5,36,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,56,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,5,10,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,4,244,2,0,0,65,0,0,4,244,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,6,19,0,0,1,61,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,128,10,1,0,0,57,0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,19,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,68,1,64,0,57,0,0,0,0,2,0,4,22],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,11,1,0,0,41,0,0,5,9,1,16,1,151,0,0,0,4,2,64,0,57,0,0,0,0,0,18,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,11,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,20,1,16,1,199,0,0,128,10,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,8,149,0,0,97,61,0,0,0,11,1,0,0,41],[0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61,0,0,0,11,1,0,0,41,0,0,0,64,0,16,4,63],[0,0,7,204,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,8,101,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,8,93,0,0,65,61,0,0,0,0,6,4,0,75,0,0,8,116,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,8,133,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,8,125,0,0,65,61,0,0,0,0,6,4,0,75,0,0,8,148,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,8,165,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,8,157,0,0,65,61,0,0,0,0,6,4,0,75,0,0,8,180,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,3,253,0,0,1,61,0,0,0,1,4,64,3,103,0,0,5,26,5,16,0,156,0,0,8,199,0,0,65,61],[0,0,5,10,1,0,0,65,0,0,0,11,2,0,0,41,0,0,0,0,0,18,4,53,0,0,0,32,1,0,0,57],[0,0,0,4,3,0,0,41,0,0,0,0,0,19,4,53,0,0,0,8,1,0,0,57,0,0,0,3,3,0,0,41],[0,0,0,0,0,19,4,53,0,0,0,68,1,32,0,57,0,0,5,34,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,2,1,0,0,41,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,0,2,35,0,73],[0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223,0,0,0,192,1,16,2,16,0,0,5,27,1,16,1,151],[0,0,5,28,1,16,1,199,0,0,0,0,1,18,3,175,0,0,0,7,2,0,0,41,0,0,0,8,13,0,0,41],[19,201,19,195,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,9,209,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,29,2,32,1,151],[0,0,0,64,4,0,4,61,0,0,0,0,2,36,0,25,0,11,0,0,0,4,0,29,0,0,0,0,4,66,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,7,5,32,0,156,0,0,3,211,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,3,211,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,11,2,0,0,41],[0,0,0,0,8,50,4,54,0,0,0,31,2,48,0,57,0,0,0,5,2,32,2,114,0,0,8,243,0,0,97,61],[0,0,0,0,4,0,0,49,0,0,0,1,4,64,3,103,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,104,0,25,0,0,0,0,6,100,3,79,0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,8,235,0,0,65,61,0,9,0,0,0,8,0,29],[0,0,0,0,2,0,0,75,0,0,8,246,0,0,97,61,0,0,0,31,2,48,1,143,0,0,0,5,3,48,2,114],[0,0,0,9,7,0,0,41,0,0,9,3,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,5,64,2,16],[0,0,0,0,6,87,0,25,0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,0,0,0,0,86,4,53],[0,0,0,1,4,64,0,57,0,0,0,0,5,52,0,75,0,0,8,251,0,0,65,61,0,0,0,0,4,2,0,75],[0,0,9,18,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,9,3,48,0,41],[0,0,0,3,2,32,2,16,0,0,0,0,4,3,4,51,0,0,0,0,4,36,1,207,0,0,0,0,4,36,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207],[0,0,0,0,1,65,1,159,0,0,0,0,0,19,4,53,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,1,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20],[0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,7,102,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,30,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,10,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,9,236,0,0,97,61,0,0,0,10,1,0,0,41],[0,0,5,7,1,16,0,156,0,0,3,211,0,0,33,61,0,0,0,10,1,0,0,41,0,0,0,64,0,16,4,63],[0,0,0,11,1,0,0,41,0,0,0,0,1,1,4,51,0,0,5,8,2,0,0,65,0,0,0,32,3,16,0,140],[0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25,0,0,5,8,4,16,1,151,0,0,0,0,5,4,0,75],[0,0,0,0,2,0,160,25,0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75],[0,0,7,102,0,0,193,61,0,0,0,9,2,0,0,41,0,0,0,0,2,2,4,51,0,0,5,7,3,32,0,156],[0,0,7,102,0,0,33,61,0,0,0,9,1,16,0,41,0,0,0,9,2,32,0,41,0,0,0,31,3,32,0,57],[0,0,5,8,4,0,0,65,0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25],[0,0,5,8,3,48,1,151,0,0,5,8,6,16,1,151,0,0,0,0,7,99,0,75,0,0,0,0,4,0,128,25],[0,0,0,0,3,99,1,63,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75],[0,0,7,102,0,0,193,61,0,0,0,0,35,2,4,52,0,0,5,7,4,48,0,156,0,0,3,211,0,0,33,61],[0,0,0,5,4,48,2,16,0,0,0,63,4,64,0,57,0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111],[0,0,0,10,4,64,0,41,0,0,5,7,5,64,0,156,0,0,3,211,0,0,33,61,0,0,0,64,0,64,4,63],[0,0,0,10,4,0,0,41,0,0,0,0,0,52,4,53,0,0,0,6,3,48,2,16,0,0,0,0,3,35,0,25],[0,0,0,0,4,19,0,75,0,0,7,102,0,0,33,61,0,0,0,0,4,50,0,75,0,0,9,140,0,0,129,61],[0,0,5,8,4,0,0,65,0,0,0,10,5,0,0,41,0,0,0,0,6,33,0,73,0,0,0,64,7,96,0,140],[0,0,0,0,7,0,0,25,0,0,0,0,7,4,64,25,0,0,5,8,6,96,1,151,0,0,0,0,8,6,0,75],[0,0,0,0,8,0,0,25,0,0,0,0,8,4,32,25,0,0,5,8,6,96,0,156,0,0,0,0,8,7,192,25],[0,0,0,0,6,8,0,75,0,0,7,102,0,0,193,61,0,0,0,64,6,0,4,61,0,0,5,32,7,96,0,156],[0,0,3,211,0,0,33,61,0,0,0,32,5,80,0,57,0,0,0,64,7,96,0,57,0,0,0,64,0,112,4,63],[0,0,0,0,135,2,4,52,0,0,0,0,7,118,4,54,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53],[0,0,0,0,0,101,4,53,0,0,0,64,2,32,0,57,0,0,0,0,6,50,0,75,0,0,9,114,0,0,65,61],[0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57,0,0,128,5,1,0,0,57,0,0,0,4,0,16,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,9,208,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,7,102,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,36,1,48,0,57,0,0,0,64,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,5,33,1,0,0,65,0,0,0,0,0,19,4,53,0,0,0,4,1,48,0,57],[0,0,0,7,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,10,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,0,68,2,48,0,57,0,0,0,0,0,18,4,53,0,11,0,0,0,3,0,29,0,0,0,100,2,48,0,57],[0,0,0,0,3,1,0,75,0,0,9,187,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,10,4,0,0,41],[0,0,0,32,4,64,0,57,0,10,0,0,0,4,0,29,0,0,0,0,4,4,4,51,0,0,0,0,84,4,4,52],[0,0,0,0,4,66,4,54,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,64,2,32,0,57],[0,0,0,1,3,48,0,57,0,0,0,0,4,19,0,75,0,0,9,175,0,0,65,61,0,0,0,11,4,0,0,41],[0,0,0,0,1,66,0,73,0,0,4,244,2,0,0,65,0,0,4,244,3,64,0,156,0,0,0,0,3,2,0,25],[0,0,0,0,3,4,64,25,0,0,0,64,3,48,2,16,0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16,0,0,0,0,1,33,1,159,0,0,128,5,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,10,12,0,0,97,61,0,0,7,8,0,0,1,61],[0,0,0,0,0,1,4,47,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,9,220,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,9,213,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,9,234,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,9,252,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,9,244,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,10,11,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,10,28,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,10,20,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,10,43,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,3,253,0,0,1,61],[0,0,0,31,3,16,0,57,0,0,5,8,4,0,0,65,0,0,0,0,5,35,0,75,0,0,0,0,5,0,0,25],[0,0,0,0,5,4,64,25,0,0,5,8,6,32,1,151,0,0,5,8,3,48,1,151,0,0,0,0,7,99,0,75],[0,0,0,0,4,0,160,25,0,0,0,0,3,99,1,63,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25],[0,0,0,0,3,4,0,75,0,0,10,68,0,0,97,61,0,0,0,1,3,16,3,103,0,0,0,0,3,3,4,59],[0,0,5,7,4,48,0,156,0,0,10,68,0,0,33,61,0,0,0,32,1,16,0,57,0,0,0,0,4,49,0,25],[0,0,0,0,2,36,0,75,0,0,10,68,0,0,33,61,0,0,0,0,2,3,0,25,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,19,203,0,1,4,48,0,3,0,0,0,0,0,2,0,0,0,0,7,0,4,20],[0,0,0,0,8,69,0,25,0,0,0,0,5,88,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,4,244,4,64,1,151,0,0,0,1,5,80,1,144,0,0,10,206,0,0,193,61,0,0,0,0,6,0,0,49],[0,0,0,0,5,134,0,75,0,0,10,206,0,0,65,61,0,2,0,0,0,2,0,29,0,3,0,0,0,1,0,29],[0,1,0,0,0,3,0,29,0,0,0,1,4,64,3,103,0,0,5,26,5,112,0,156,0,0,10,216,0,0,129,61],[0,0,0,0,2,134,0,73,0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223,0,0,0,192,1,112,2,16],[0,0,5,27,1,16,1,151,0,0,5,71,1,16,1,199,0,0,0,0,1,18,3,175,0,0,128,16,2,0,0,57],[19,201,19,190,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,10,223,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,29,4,32,1,151],[0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,5,7,6,64,0,156,0,0,10,210,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,10,210,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57],[0,0,0,5,5,80,2,114,0,0,10,129,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,10,121,0,0,65,61,0,0,0,0,5,0,0,75,0,0,10,131,0,0,97,61,0,0,0,31,5,48,1,143],[0,0,0,5,3,48,2,114,0,0,10,143,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,10,135,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,10,158,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,64,1,0,4,61,0,0,0,0,2,2,4,51],[0,0,0,32,2,32,0,140,0,0,0,3,5,0,0,41,0,0,0,2,6,0,0,41,0,0,10,250,0,0,193,61],[0,0,0,0,2,4,4,51,0,0,0,160,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,128,2,16,0,57],[0,0,0,0,0,98,4,53,0,0,0,96,2,16,0,57,0,0,0,1,3,0,0,41,0,0,0,0,0,50,4,53],[0,0,5,9,2,80,1,151,0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57],[0,0,5,73,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,160,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,5,74,3,16,0,156,0,0,10,210,0,0,33,61,0,0,0,192,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,4,244,3,0,0,65,0,0,4,244,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,4,244,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,4,244,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,39,1,16,1,199,0,0,128,16,2,0,0,57],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,11,11,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,5,9,1,16,1,151,0,0,0,0,0,1,4,45,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,17,1,0,0,57,0,0,10,213,0,0,1,61,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,5,34,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57,0,0,10,255,0,0,1,61,0,0,0,31,4,48,1,143],[0,0,0,5,2,48,2,114,0,0,10,234,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,37,0,75,0,0,10,227,0,0,65,61,0,0,0,0,5,4,0,75,0,0,10,248,0,0,97,61],[0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207],[0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53],[0,0,0,96,1,48,2,16,0,0,19,203,0,1,4,48,0,0,0,68,2,16,0,57,0,0,5,72,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,5,10,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,4,244,2,0,0,65,0,0,4,244,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,0,1,0,0,25],[0,0,19,203,0,1,4,48,0,0,0,64,3,0,4,61,0,0,0,96,4,48,0,57,0,0,0,0,0,36,4,53],[0,0,5,9,1,16,1,151,0,0,0,64,2,48,0,57,0,0,0,0,0,18,4,53,0,0,0,96,1,0,0,57],[0,0,0,0,1,19,4,54,0,0,5,75,2,0,0,65,0,0,0,0,0,33,4,53,0,0,5,76,2,48,0,156],[0,0,11,49,0,0,129,61,0,0,0,128,2,48,0,57,0,0,0,64,0,32,4,63,0,0,4,244,2,0,0,65],[0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,0,3,3,4,51],[0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,96,3,48,2,16,0,0,0,0,1,19,1,159],[0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,5,39,1,16,1,199,0,0,128,16,2,0,0,57,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,11,55,0,0,97,61,0,0,0,0,1,1,4,59,0,0,5,9,1,16,1,151],[0,0,0,0,0,1,4,45,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48,0,0,0,0,1,0,0,25],[0,0,19,203,0,1,4,48,0,9,0,0,0,0,0,2,0,5,0,0,0,3,0,29,0,0,0,64,5,0,4,61],[0,0,0,4,3,80,0,57,0,8,0,0,0,1,0,29,0,0,0,0,1,1,0,75,0,0,14,5,0,0,97,61],[0,4,0,0,0,4,0,29,0,3,0,0,0,2,0,29,0,0,5,9,1,32,1,151,0,0,255,255,2,16,0,140],[0,0,14,21,0,0,161,61,0,0,5,77,2,0,0,65,0,0,0,0,0,37,4,53,0,9,0,0,0,1,0,29],[0,0,0,0,0,19,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,80,0,156,0,0,0,0,1,5,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57],[0,6,0,0,0,2,0,29,0,7,0,0,0,5,0,29,19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,11,106,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,11,98,0,0,65,61,0,0,0,0,7,5,0,75,0,0,11,121,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,14,40,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25,0,0,0,0,1,20,0,75,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,64,57,0,0,5,7,2,64,0,156,0,0,13,246,0,0,33,61,0,0,0,1,1,16,1,144],[0,0,13,246,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,31,1,48,0,140,0,0,13,244,0,0,161,61],[0,0,0,4,1,64,0,57,0,0,0,0,2,10,4,51,0,0,0,0,2,2,0,75,0,0,14,69,0,0,193,61],[0,0,5,79,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,3,2,0,0,57,0,7,0,0,0,4,0,29],[19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,11,176,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,11,168,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,11,191,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,14,79,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25],[0,0,5,7,1,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140],[0,0,13,244,0,0,65,61,0,0,0,4,1,64,0,57,0,0,0,0,2,10,4,51,0,0,0,0,2,2,0,75],[0,0,14,108,0,0,193,61,0,0,5,13,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,8,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,4,2,0,0,57],[0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,11,241,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,11,233,0,0,65,61,0,0,0,0,7,5,0,75,0,0,12,0,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,0,0,1,2,32,1,144,0,0,14,118,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143],[0,0,0,0,4,161,0,25,0,0,5,7,1,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,64,4,63],[0,0,0,32,1,48,0,140,0,0,13,244,0,0,65,61,0,0,0,0,1,10,4,51,0,0,0,0,1,1,0,75],[0,0,14,147,0,0,97,61,0,0,5,32,1,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,1,64,0,57],[0,0,0,64,0,16,4,63,0,0,0,0,1,4,4,54,0,2,0,0,0,1,0,29,0,0,0,0,0,1,4,53],[0,0,0,9,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,15,1,16,1,199,0,0,128,16,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15],[0,0,0,7,3,0,0,41,0,0,0,1,2,32,1,144,0,0,13,244,0,0,97,61,0,0,0,0,2,3,4,51],[0,0,0,2,3,32,0,140,0,0,13,253,0,0,129,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,2,3,0,0,41,0,0,0,0,3,3,4,51,0,0,0,1,4,48,0,140,0,0,13,253,0,0,33,61],[0,0,5,16,4,0,0,65,0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143],[0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27,0,0,0,0,1,0,4,22,0,0,5,17,2,0,0,65],[0,0,0,0,0,32,4,57,0,0,0,0,1,1,0,75,0,0,12,159,0,0,97,61,0,0,128,10,1,0,0,57],[0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57],[0,7,0,0,0,2,0,29,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,19,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,68,1,64,0,57,0,0,0,0,2,0,4,22],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,0,1,0,4,16,0,0,5,9,1,16,1,151,0,0,0,4,2,64,0,57,0,0,0,0,0,18,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,2,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,20,1,16,1,199,0,0,128,10,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,15,16,0,0,97,61,0,0,0,2,2,0,0,41],[0,0,5,7,1,32,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,32,4,63,0,0,5,17,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,7,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65],[0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16],[0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57,0,0,0,9,1,0,0,41],[0,2,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,41,0,0,5,22,1,16,1,151],[0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57,0,1,0,0,0,2,0,29,0,0,0,0,0,18,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,7,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,15,48,0,0,97,61,0,0,0,7,6,0,0,41],[0,0,5,7,1,96,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,96,4,63,0,0,0,0,1,0,4,22],[0,0,5,25,1,16,1,151,0,0,0,0,0,1,4,23,0,0,12,205,0,0,1,61,0,0,0,6,2,0,0,41],[0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156],[0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,2,64,0,57,0,0,0,9,1,0,0,41,0,2,0,0,0,2,0,29,0,0,0,0,0,18,4,53],[0,0,0,8,1,0,0,41,0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57],[0,1,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,7,0,0,0,4,0,29],[0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,15,80,0,0,97,61,0,0,0,7,6,0,0,41,0,0,5,7,1,96,0,156,0,0,13,246,0,0,33,61],[0,0,0,64,0,96,4,63,0,0,0,0,1,0,4,20,0,0,0,5,4,0,0,41,0,0,0,4,2,64,0,41],[0,0,0,4,3,32,0,108,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,4,244,4,64,1,151],[0,0,0,1,3,48,1,144,0,0,14,1,0,0,193,61,0,0,0,0,3,0,0,49,0,0,0,0,5,35,0,75],[0,0,14,1,0,0,65,61,0,0,0,1,4,64,3,103,0,0,5,26,5,16,0,156,0,0,14,164,0,0,129,61],[0,0,0,0,5,0,4,17,0,0,0,0,2,35,0,73,0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223],[0,0,0,192,1,16,2,16,0,0,5,27,1,16,1,151,0,0,5,28,1,16,1,199,0,0,0,0,1,18,3,175],[0,4,0,0,0,5,0,29,0,0,5,9,13,80,1,151,0,0,0,3,2,0,0,41,19,201,19,195,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,14,181,0,0,97,61,0,0,0,63,2,48,0,57,0,0,5,29,2,32,1,151,0,0,0,64,6,0,4,61],[0,0,0,0,2,38,0,25,0,0,0,0,4,98,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,5,7,5,32,0,156,0,0,13,246,0,0,33,61,0,0,0,1,4,64,1,144,0,0,13,246,0,0,193,61],[0,0,0,64,0,32,4,63,0,5,0,0,0,6,0,29,0,0,0,0,8,54,4,54,0,0,0,31,2,48,0,57],[0,0,0,5,2,32,2,114,0,0,13,9,0,0,97,61,0,0,0,0,4,0,0,49,0,0,0,1,4,64,3,103],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,100,3,79],[0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,13,1,0,0,65,61,0,0,0,0,2,0,0,75,0,0,13,11,0,0,97,61,0,0,0,31,2,48,1,143],[0,0,0,5,3,48,2,114,0,0,13,23,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,5,64,2,16],[0,0,0,0,6,88,0,25,0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,0,0,0,0,86,4,53],[0,0,0,1,4,64,0,57,0,0,0,0,5,52,0,75,0,0,13,15,0,0,65,61,0,0,0,0,4,2,0,75],[0,0,13,38,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,56,0,25],[0,0,0,3,2,32,2,16,0,0,0,0,4,3,4,51,0,0,0,0,4,36,1,207,0,0,0,0,4,36,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207],[0,0,0,0,1,65,1,159,0,0,0,0,0,19,4,53,0,7,0,0,0,8,0,29,0,0,5,17,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,0,6,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65],[0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16],[0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,13,252,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,13,244,0,0,97,61,0,0,0,64,4,0,4,61],[0,0,5,30,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,9,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,6,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,14,208,0,0,97,61],[0,0,0,6,9,0,0,41,0,0,5,7,1,144,0,156,0,0,0,5,1,0,0,41,0,0,13,246,0,0,33,61],[0,0,0,64,0,144,4,63,0,0,0,0,1,1,4,51,0,0,5,8,2,0,0,65,0,0,0,32,3,16,0,140],[0,0,0,0,3,0,0,25,0,0,0,0,3,2,64,25,0,0,5,8,4,16,1,151,0,0,0,0,5,4,0,75],[0,0,0,0,2,0,160,25,0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75],[0,0,13,244,0,0,193,61,0,0,0,7,2,0,0,41,0,0,0,0,2,2,4,51,0,0,5,7,3,32,0,156],[0,0,13,244,0,0,33,61,0,0,0,7,1,16,0,41,0,0,0,7,2,32,0,41,0,0,0,31,3,32,0,57],[0,0,5,8,4,0,0,65,0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25],[0,0,5,8,3,48,1,151,0,0,5,8,6,16,1,151,0,0,0,0,7,99,0,75,0,0,0,0,4,0,128,25],[0,0,0,0,3,99,1,63,0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75],[0,0,13,244,0,0,193,61,0,0,0,0,35,2,4,52,0,0,5,7,4,48,0,156,0,0,13,246,0,0,33,61],[0,0,0,5,4,48,2,16,0,0,0,63,4,64,0,57,0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111],[0,0,0,0,4,148,0,25,0,0,5,7,5,64,0,156,0,0,13,246,0,0,33,61,0,0,0,64,0,64,4,63],[0,0,0,0,0,57,4,53,0,0,0,6,3,48,2,16,0,0,0,0,3,35,0,25,0,0,0,0,4,19,0,75],[0,0,13,244,0,0,33,61,0,0,0,0,4,50,0,75,0,0,13,159,0,0,129,61,0,0,5,8,4,0,0,65],[0,0,0,0,5,9,0,25,0,0,0,0,6,33,0,73,0,0,0,64,7,96,0,140,0,0,0,0,7,0,0,25],[0,0,0,0,7,4,64,25,0,0,5,8,6,96,1,151,0,0,0,0,8,6,0,75,0,0,0,0,8,0,0,25],[0,0,0,0,8,4,32,25,0,0,5,8,6,96,0,156,0,0,0,0,8,7,192,25,0,0,0,0,6,8,0,75],[0,0,13,244,0,0,193,61,0,0,0,64,6,0,4,61,0,0,5,32,7,96,0,156,0,0,13,246,0,0,33,61],[0,0,0,32,5,80,0,57,0,0,0,64,7,96,0,57,0,0,0,64,0,112,4,63,0,0,0,0,135,2,4,52],[0,0,0,0,7,118,4,54,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,0,101,4,53],[0,0,0,64,2,32,0,57,0,0,0,0,6,50,0,75,0,0,13,133,0,0,65,61,0,0,5,17,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,128,5,1,0,0,57,0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,13,252,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,0,6,6,0,0,41],[0,0,13,244,0,0,97,61,0,0,0,64,7,0,4,61,0,0,0,36,1,112,0,57,0,0,0,64,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,5,33,1,0,0,65,0,0,0,0,0,23,4,53,0,0,0,4,1,112,0,57],[0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,0,1,6,4,51,0,0,0,68,2,112,0,57],[0,0,0,0,0,18,4,53,0,0,0,100,2,112,0,57,0,0,0,0,3,1,0,75,0,0,13,203,0,0,97,61],[0,0,0,0,3,0,0,25,0,0,0,32,6,96,0,57,0,0,0,0,4,6,4,51,0,0,0,0,84,4,4,52],[0,0,0,0,4,66,4,54,0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,64,2,32,0,57],[0,0,0,1,3,48,0,57,0,0,0,0,4,19,0,75,0,0,13,193,0,0,65,61,0,0,0,0,1,114,0,73],[0,0,4,244,2,0,0,65,0,0,4,244,3,112,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,7,64,25],[0,0,0,64,3,48,2,16,0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,49,1,159,0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,192,2,48,2,16,0,0,0,0,1,33,1,159,0,0,128,5,2,0,0,57,0,7,0,0,0,7,0,29],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,14,240,0,0,97,61,0,0,0,7,2,0,0,41],[0,0,5,7,1,32,0,156,0,0,0,0,1,2,0,25,0,0,13,246,0,0,33,61,0,0,0,64,0,16,4,63],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,4,3,0,0,57],[0,0,5,40,4,0,0,65,0,0,0,4,5,0,0,41,0,0,0,8,6,0,0,41,0,0,0,9,7,0,0,41],[19,201,19,180,0,0,4,15,0,0,0,1,1,32,1,144,0,0,13,244,0,0,97,61,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,19,203,0,1,4,48,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48],[0,0,0,0,0,1,4,47,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,33,1,0,0,57],[0,0,13,249,0,0,1,61,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,13,249,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,37,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,35,4,53,0,0,0,68,1,80,0,57,0,0,5,83,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,80,0,57,0,0,0,27,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,5,20,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,5,10,2,0,0,65,0,0,0,0,0,37,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,35,4,53,0,0,0,100,1,80,0,57,0,0,5,81,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,68,1,80,0,57,0,0,5,82,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,80,0,57],[0,0,0,40,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,4,244,2,80,0,156],[0,0,0,0,5,1,128,25,0,0,0,64,1,80,2,16,0,0,5,37,1,16,1,199,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,14,53,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,14,45,0,0,65,61,0,0,0,0,6,4,0,75,0,0,15,111,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,15,111,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,78,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,21,2,0,0,57,0,0,14,157,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,14,92,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,84,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,14,107,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,0,68,1,64,0,57,0,0,5,80,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,19,2,0,0,57,0,0,14,157,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,14,131,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,123,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,14,146,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61,0,0,0,68,1,64,0,57],[0,0,5,41,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,26,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,5,10,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57],[0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,4,244,2,64,0,156],[0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48],[0,0,5,10,1,0,0,65,0,0,0,0,0,22,4,53,0,0,0,32,1,0,0,57,0,0,0,2,2,0,0,41],[0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,57,0,0,0,1,2,0,0,41,0,0,0,0,0,18,4,53],[0,0,0,68,1,96,0,57,0,0,5,34,2,0,0,65,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,96,0,156,0,0,0,0,6,1,128,25,0,0,0,64,1,96,2,16,0,0,5,20,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,14,192,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,14,185,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,14,206,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,19,203,0,1,4,48],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,14,224,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,216,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,14,239,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,0,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,14,248,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,15,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,32,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,15,24,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,47,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,64,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,15,56,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,79,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,15,111,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143],[0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,15,96,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,15,88,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,15,111,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,19,203,0,1,4,48,0,9,0,0,0,0,0,2,0,3,0,0,0,5,0,29],[0,4,0,0,0,4,0,29,0,5,0,0,0,3,0,29,0,0,0,64,4,0,4,61,0,0,0,4,3,64,0,57],[0,8,0,0,0,1,0,29,0,0,0,0,1,1,0,75,0,0,18,72,0,0,97,61,0,2,0,0,0,2,0,29],[0,0,5,9,1,32,1,151,0,0,255,255,2,16,0,140,0,0,18,82,0,0,161,61,0,0,5,77,2,0,0,65],[0,0,0,0,0,36,4,53,0,9,0,0,0,1,0,29,0,0,0,0,0,19,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57,0,6,0,0,0,2,0,29,0,7,0,0,0,4,0,29],[19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,15,168,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,15,160,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,15,183,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,18,101,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25],[0,0,0,0,1,20,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57,0,0,5,7,2,64,0,156],[0,0,18,57,0,0,33,61,0,0,0,1,1,16,1,144,0,0,18,57,0,0,193,61,0,0,0,64,0,64,4,63],[0,0,0,31,1,48,0,140,0,0,18,55,0,0,161,61,0,0,0,4,1,64,0,57,0,0,0,0,2,10,4,51],[0,0,0,0,2,2,0,75,0,0,18,130,0,0,193,61,0,0,5,79,2,0,0,65,0,0,0,0,0,36,4,53],[0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199],[0,0,128,3,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15,0,0,0,7,10,0,0,41],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,15,238,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,138,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,15,230,0,0,65,61,0,0,0,0,7,5,0,75,0,0,15,253,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,18,140,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25,0,0,5,7,1,64,0,156,0,0,18,57,0,0,33,61],[0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140,0,0,18,55,0,0,65,61,0,0,0,4,1,64,0,57],[0,0,0,0,2,10,4,51,0,0,0,0,2,2,0,75,0,0,18,169,0,0,193,61,0,0,5,13,2,0,0,65],[0,0,0,0,0,36,4,53,0,0,0,8,2,0,0,41,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,5,31,1,16,1,199,0,0,128,4,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15],[0,0,0,7,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,16,47,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,16,39,0,0,65,61,0,0,0,0,7,5,0,75],[0,0,16,62,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,0,6,106,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47],[0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207],[0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,18,179,0,0,97,61],[0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,4,161,0,25,0,0,5,7,1,64,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140,0,0,18,55,0,0,65,61],[0,0,0,0,1,10,4,51,0,0,0,0,1,1,0,75,0,0,18,208,0,0,97,61,0,0,5,32,1,64,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,1,64,0,57,0,0,0,64,0,16,4,63,0,0,0,0,3,4,4,54],[0,0,0,0,0,3,4,53,0,0,0,5,2,0,0,41,0,0,0,2,1,32,0,140,0,0,18,64,0,0,129,61],[0,0,0,0,0,36,4,53,0,5,0,0,0,3,0,29,0,0,0,0,0,3,4,53,0,0,0,9,1,0,0,41],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,15,1,16,1,199],[0,0,128,16,2,0,0,57,0,7,0,0,0,4,0,29,19,201,19,185,0,0,4,15,0,0,0,7,3,0,0,41],[0,0,0,1,2,32,1,144,0,0,18,55,0,0,97,61,0,0,0,0,2,3,4,51,0,0,0,1,3,32,0,140],[0,0,0,5,5,0,0,41,0,0,18,64,0,0,33,61,0,0,0,0,1,1,4,59,0,0,0,0,3,1,4,26],[0,0,1,0,4,0,0,138,0,0,0,0,3,67,1,111,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,0,3,5,4,51,0,0,0,1,4,48,0,140,0,0,18,64,0,0,33,61,0,0,5,16,4,0,0,65],[0,0,0,0,2,66,1,111,0,0,0,8,3,48,2,16,0,0,255,0,3,48,1,143,0,0,0,0,2,35,1,159],[0,0,0,0,0,33,4,27,0,0,0,0,1,0,4,22,0,0,5,17,2,0,0,65,0,0,0,0,0,32,4,57],[0,0,0,0,1,1,0,75,0,0,16,226,0,0,97,61,0,0,128,10,1,0,0,57,0,0,0,4,0,16,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199,0,0,128,2,2,0,0,57,0,7,0,0,0,2,0,29],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,19,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,68,1,64,0,57,0,0,0,0,2,0,4,22,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53,0,0,0,0,1,0,4,16],[0,0,5,9,1,16,1,151,0,0,0,4,2,64,0,57,0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,5,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,20,1,16,1,199,0,0,128,10,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,19,77,0,0,97,61,0,0,0,5,2,0,0,41,0,0,5,7,1,32,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,0,32,4,63,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,7,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20],[0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57,0,0,0,9,1,0,0,41,0,5,0,0,0,2,0,29],[0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,41,0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199],[0,0,0,36,2,64,0,57,0,1,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156],[0,7,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16],[0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199,0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,19,109,0,0,97,61,0,0,0,7,6,0,0,41,0,0,5,7,1,96,0,156],[0,0,18,57,0,0,33,61,0,0,0,64,0,96,4,63,0,0,0,0,1,0,4,22,0,0,5,25,1,16,1,151],[0,0,0,0,0,1,4,23,0,0,17,16,0,0,1,61,0,0,0,6,2,0,0,41,0,0,0,4,0,32,4,67],[0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20,0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25],[0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,5,21,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,2,64,0,57],[0,0,0,9,1,0,0,41,0,5,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,41],[0,0,5,22,1,16,1,151,0,0,5,23,1,16,1,199,0,0,0,36,2,64,0,57,0,1,0,0,0,2,0,29],[0,0,0,0,0,18,4,53,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,4,244,3,64,0,156,0,7,0,0,0,4,0,29,0,0,0,0,1,4,64,25],[0,0,0,64,1,16,2,16,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,24,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,19,141,0,0,97,61],[0,0,0,7,6,0,0,41,0,0,5,7,1,96,0,156,0,0,18,57,0,0,33,61,0,0,0,64,0,96,4,63],[0,0,0,0,1,0,4,20,0,0,0,4,4,0,0,41,0,0,0,3,2,64,0,41,0,0,0,3,3,32,0,108],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,4,244,4,64,1,151,0,0,0,1,3,48,1,144],[0,0,18,68,0,0,193,61,0,0,0,0,3,0,0,49,0,0,0,0,5,35,0,75,0,0,18,68,0,0,65,61],[0,0,0,1,4,64,3,103,0,0,5,26,5,16,0,156,0,0,18,225,0,0,129,61,0,0,0,0,5,0,4,17],[0,0,0,0,2,35,0,73,0,0,4,244,2,32,1,151,0,0,0,0,2,36,3,223,0,0,0,192,1,16,2,16],[0,0,5,27,1,16,1,151,0,0,5,28,1,16,1,199,0,0,0,0,1,18,3,175,0,4,0,0,0,5,0,29],[0,0,5,9,13,80,1,151,0,0,0,2,2,0,0,41,19,201,19,195,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,4,244,3,48,1,151,0,0,0,1,2,32,1,144,0,0,18,242,0,0,97,61],[0,0,0,63,2,48,0,57,0,0,5,29,2,32,1,151,0,0,0,64,6,0,4,61,0,0,0,0,2,38,0,25],[0,0,0,0,4,98,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,5,7,5,32,0,156],[0,0,18,57,0,0,33,61,0,0,0,1,4,64,1,144,0,0,18,57,0,0,193,61,0,0,0,64,0,32,4,63],[0,5,0,0,0,6,0,29,0,0,0,0,8,54,4,54,0,0,0,31,2,48,0,57,0,0,0,5,2,32,2,114],[0,0,17,76,0,0,97,61,0,0,0,0,4,0,0,49,0,0,0,1,4,64,3,103,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,100,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,17,68,0,0,65,61],[0,0,0,0,2,0,0,75,0,0,17,78,0,0,97,61,0,0,0,31,2,48,1,143,0,0,0,5,3,48,2,114],[0,0,17,90,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,5,64,2,16,0,0,0,0,6,88,0,25],[0,0,0,0,5,81,3,79,0,0,0,0,5,5,4,59,0,0,0,0,0,86,4,53,0,0,0,1,4,64,0,57],[0,0,0,0,5,52,0,75,0,0,17,82,0,0,65,61,0,0,0,0,4,2,0,75,0,0,17,105,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,56,0,25,0,0,0,3,2,32,2,16],[0,0,0,0,4,3,4,51,0,0,0,0,4,36,1,207,0,0,0,0,4,36,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,2,32,0,137,0,0,0,0,1,33,2,47,0,0,0,0,1,33,1,207,0,0,0,0,1,65,1,159],[0,0,0,0,0,19,4,53,0,7,0,0,0,8,0,29,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,0,6,2,0,0,41,0,0,0,4,0,32,4,67,0,0,4,244,1,0,0,65,0,0,0,0,4,0,4,20],[0,0,4,244,3,64,0,156,0,0,0,0,4,1,128,25,0,0,0,192,1,64,2,16,0,0,5,18,1,16,1,199],[19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,1,1,0,75,0,0,18,55,0,0,97,61,0,0,0,64,4,0,4,61,0,0,5,30,1,0,0,65],[0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,9,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,4,244,3,64,0,156,0,6,0,0,0,4,0,29,0,0,0,0,1,4,64,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,5,31,1,16,1,199,0,0,128,2,2,0,0,57],[19,201,19,180,0,0,4,15,0,0,0,1,2,32,1,144,0,0,19,13,0,0,97,61,0,0,0,6,9,0,0,41],[0,0,5,7,1,144,0,156,0,0,0,5,1,0,0,41,0,0,18,57,0,0,33,61,0,0,0,64,0,144,4,63],[0,0,0,0,1,1,4,51,0,0,5,8,2,0,0,65,0,0,0,32,3,16,0,140,0,0,0,0,3,0,0,25],[0,0,0,0,3,2,64,25,0,0,5,8,4,16,1,151,0,0,0,0,5,4,0,75,0,0,0,0,2,0,160,25],[0,0,5,8,4,64,0,156,0,0,0,0,2,3,192,25,0,0,0,0,2,2,0,75,0,0,18,55,0,0,193,61],[0,0,0,7,2,0,0,41,0,0,0,0,2,2,4,51,0,0,5,7,3,32,0,156,0,0,18,55,0,0,33,61],[0,0,0,7,1,16,0,41,0,0,0,7,2,32,0,41,0,0,0,31,3,32,0,57,0,0,5,8,4,0,0,65],[0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25,0,0,5,8,3,48,1,151],[0,0,5,8,6,16,1,151,0,0,0,0,7,99,0,75,0,0,0,0,4,0,128,25,0,0,0,0,3,99,1,63],[0,0,5,8,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75,0,0,18,55,0,0,193,61],[0,0,0,0,35,2,4,52,0,0,5,7,4,48,0,156,0,0,18,57,0,0,33,61,0,0,0,5,4,48,2,16],[0,0,0,63,4,64,0,57,0,0,0,32,5,0,0,138,0,0,0,0,4,84,1,111,0,0,0,0,4,148,0,25],[0,0,5,7,5,64,0,156,0,0,18,57,0,0,33,61,0,0,0,64,0,64,4,63,0,0,0,0,0,57,4,53],[0,0,0,6,3,48,2,16,0,0,0,0,3,35,0,25,0,0,0,0,4,19,0,75,0,0,18,55,0,0,33,61],[0,0,0,0,4,50,0,75,0,0,17,226,0,0,129,61,0,0,5,8,4,0,0,65,0,0,0,0,5,9,0,25],[0,0,0,0,6,33,0,73,0,0,0,64,7,96,0,140,0,0,0,0,7,0,0,25,0,0,0,0,7,4,64,25],[0,0,5,8,6,96,1,151,0,0,0,0,8,6,0,75,0,0,0,0,8,0,0,25,0,0,0,0,8,4,32,25],[0,0,5,8,6,96,0,156,0,0,0,0,8,7,192,25,0,0,0,0,6,8,0,75,0,0,18,55,0,0,193,61],[0,0,0,64,6,0,4,61,0,0,5,32,7,96,0,156,0,0,18,57,0,0,33,61,0,0,0,32,5,80,0,57],[0,0,0,64,7,96,0,57,0,0,0,64,0,112,4,63,0,0,0,0,135,2,4,52,0,0,0,0,7,118,4,54],[0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,0,101,4,53,0,0,0,64,2,32,0,57],[0,0,0,0,6,50,0,75,0,0,17,200,0,0,65,61,0,0,5,17,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,128,5,1,0,0,57,0,0,0,4,0,16,4,67,0,0,4,244,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,5,18,1,16,1,199],[0,0,128,2,2,0,0,57,19,201,19,185,0,0,4,15,0,0,0,1,2,32,1,144,0,0,18,63,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,0,6,6,0,0,41,0,0,18,55,0,0,97,61],[0,0,0,64,7,0,4,61,0,0,0,36,1,112,0,57,0,0,0,64,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,5,33,1,0,0,65,0,0,0,0,0,23,4,53,0,0,0,4,1,112,0,57,0,0,0,9,2,0,0,41],[0,0,0,0,0,33,4,53,0,0,0,0,1,6,4,51,0,0,0,68,2,112,0,57,0,0,0,0,0,18,4,53],[0,0,0,100,2,112,0,57,0,0,0,0,3,1,0,75,0,0,18,14,0,0,97,61,0,0,0,0,3,0,0,25],[0,0,0,32,6,96,0,57,0,0,0,0,4,6,4,51,0,0,0,0,84,4,4,52,0,0,0,0,4,66,4,54],[0,0,0,0,5,5,4,51,0,0,0,0,0,84,4,53,0,0,0,64,2,32,0,57,0,0,0,1,3,48,0,57],[0,0,0,0,4,19,0,75,0,0,18,4,0,0,65,61,0,0,0,0,1,114,0,73,0,0,4,244,2,0,0,65],[0,0,4,244,3,112,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,7,64,25,0,0,0,64,3,48,2,16],[0,0,4,244,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159],[0,0,0,0,3,0,4,20,0,0,4,244,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,128,5,2,0,0,57,0,7,0,0,0,7,0,29,19,201,19,180,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,19,45,0,0,97,61,0,0,0,7,2,0,0,41,0,0,5,7,1,32,0,156],[0,0,0,0,1,2,0,25,0,0,18,57,0,0,33,61,0,0,0,64,0,16,4,63,0,0,4,244,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,4,244,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,5,39,1,16,1,199,0,0,128,13,2,0,0,57,0,0,0,4,3,0,0,57,0,0,5,40,4,0,0,65],[0,0,0,4,5,0,0,41,0,0,0,8,6,0,0,41,0,0,0,9,7,0,0,41,19,201,19,180,0,0,4,15],[0,0,0,1,1,32,1,144,0,0,18,55,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25],[0,0,19,203,0,1,4,48,0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,5,31,1,0,0,65,0,0,19,203,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,33,1,0,0,57,0,0,18,60,0,0,1,61],[0,0,5,58,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,18,60,0,0,1,61],[0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,35,4,53],[0,0,0,68,1,64,0,57,0,0,5,83,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,27,2,0,0,57,0,0,18,218,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53],[0,0,0,32,2,0,0,57,0,0,0,0,0,35,4,53,0,0,0,100,1,64,0,57,0,0,5,81,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,82,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,40,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,5,37,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,18,114,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,18,106,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,172,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,19,172,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53],[0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,78,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,21,2,0,0,57,0,0,18,218,0,0,1,61],[0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,18,153,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,18,145,0,0,65,61,0,0,0,0,6,4,0,75,0,0,18,168,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,5,10,2,0,0,65,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,0,68,1,64,0,57,0,0,5,80,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,36,1,64,0,57,0,0,0,19,2,0,0,57,0,0,18,218,0,0,1,61,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,18,192,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,18,184,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,18,207,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,19,172,0,0,1,61],[0,0,0,68,1,64,0,57,0,0,5,41,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,26,2,0,0,57,0,0,0,0,0,33,4,53,0,0,5,10,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,4,244,1,0,0,65],[0,0,4,244,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,5,20,1,16,1,199],[0,0,19,203,0,1,4,48,0,0,5,10,1,0,0,65,0,0,0,0,0,22,4,53,0,0,0,32,1,0,0,57],[0,0,0,5,2,0,0,41,0,0,0,0,0,18,4,53,0,0,0,8,1,0,0,57,0,0,0,1,2,0,0,41],[0,0,0,0,0,18,4,53,0,0,0,68,1,96,0,57,0,0,5,34,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,4,244,1,0,0,65,0,0,4,244,2,96,0,156,0,0,0,0,6,1,128,25,0,0,0,64,1,96,2,16],[0,0,5,20,1,16,1,199,0,0,19,203,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,18,253,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,18,246,0,0,65,61,0,0,0,0,5,4,0,75,0,0,19,11,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,19,203,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,29,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,21,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,44,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,61,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,53,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,76,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,93,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,85,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,108,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,125,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,117,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,140,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,19,172,0,0,1,61,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,31,4,48,1,143,0,0,4,244,3,48,1,151,0,0,0,5,5,48,2,114,0,0,19,157,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,19,149,0,0,65,61,0,0,0,0,6,4,0,75,0,0,19,172,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137],[0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53],[0,0,4,244,1,0,0,65,0,0,4,244,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16],[0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,19,203,0,1,4,48,0,0,0,0,0,1,4,47],[0,0,19,183,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,19,188,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,19,193,0,33,4,35,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,0,0,15,13,0,25],[0,0,19,199,0,33,4,41,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,19,201,0,0,4,50,0,0,19,202,0,1,4,46,0,0,19,203,0,1,4,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,77,83,90],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,233,241,140,22],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,236,249,91,137],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,236,249,91,138],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,243,56,95,182],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,233,241,140,23],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,236,128,103,199],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,156,77,83,91],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,187,15,214,16],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,218,55,240,127],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,56,38,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,56,39,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,123,81,15,232],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,218,31,180],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,117,152,165],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,218,51,81],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,24,9,129],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,115,101,108,102,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[76,99,20,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,255],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[87,153,82,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[79,30,27,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[255,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[194,228,255,151,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,191],[173,126,35,46,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[110,111,116,32,99,97,108,108,32,116,104,101,32,99,111,110,115,116,114,117,99,116,111,114,0,0,0,0,0,0,0,0],[84,104,101,32,118,97,108,117,101,32,109,117,115,116,32,98,101,32,122,101,114,111,32,105,102,32,119,101,32,100,111,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[13,70,81,170,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[41,10,253,174,35,26,63,192,187,174,139,26,246,54,152,176,161,215,155,33,173,23,223,3,66,223,185,82,254,116,248,229],[84,104,101,32,99,111,100,101,32,104,97,115,104,32,105,115,32,110,111,116,32,107,110,111,119,110,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[48,99,149,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[105,110,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[111,109,32,115,101,113,117,101,110,116,105,97,108,32,116,111,32,97,114,98,105,116,114,97,114,121,32,111,114,100,101,114],[73,116,32,105,115,32,111,110,108,121,32,112,111,115,115,105,98,108,101,32,116,111,32,99,104,97,110,103,101,32,102,114],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[199,84,65,148,218,179,139,22,82,243,84,57,185,180,128,109,139,113,225,19,242,207,92,19,81,203,46,207,124,131,149,154],[67,97,110,32,111,110,108,121,32,98,101,32,99,97,108,108,101,100,32,98,121,32,70,79,82,67,69,95,68,69,80,76],[79,89,69,82,32,111,114,32,67,79,77,80,76,69,88,95,85,80,71,82,65,68,69,82,95,67,79,78,84,82,65,67],[84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,128,0,0,0,0,0,0,0,0],[243,56,95,182,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,254,251],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,4,0,0,0,0,0,0,0,0,0,0,0,0],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[96,118,97,108,117,101,96,32,112,114,111,118,105,100,101,100,32,105,115,32,110,111,116,32,101,113,117,97,108,32,116,111],[32,116,104,101,32,99,111,109,98,105,110,101,100,32,96,118,97,108,117,101,96,115,32,111,102,32,100,101,112,108,111,121],[109,101,110,116,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,97,112,112,114,111,112,114,105,97,116,101,32,99,97,108,108,101,114,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0],[77,226,228,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,192],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[63,182,244,241,93,221,74,117,88,140,169,52,137,74,210,205,202,178,90,80,18,226,81,94,23,131,67,61,1,40,97,26],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,115,121,115,116,101,109,32,99,97,108,108,32],[102,108,97,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[32,32,219,169,27,48,204,0,6,24,138,247,148,194,251,48,221,133,32,219,126,44,8,139,127,199,193,3,192,12,164,148],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,63],[99,186,227,169,149,29,56,232,163,251,183,183,9,9,175,193,32,6,16,252,91,197,90,222,36,47,129,89,116,103,79,35],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,128],[224,63,225,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,111,100,101,32,104,97,115,104,32,105,115,32,110,111,110,45,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0],[90,169,182,181,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[65,99,99,111,117,110,116,32,105,115,32,111,99,99,117,112,105,101,100,0,0,0,0,0,0,0,0,0,0,0,0,0],[101,108,32,115,112,97,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,110,32,110,111,116,32,100,101,112,108,111,121,32,99,111,110,116,114,97,99,116,115,32,105,110,32,107,101,114,110],[66,121,116,101,99,111,100,101,72,97,115,104,32,99,97,110,110,111,116,32,98,101,32,122,101,114,111,0,0,0,0,0],[240,216,92,27,130,178,83,239,156,199,86,153,75,62,76,240,236,53,132,231,151,139,5,161,93,133,7,213,47,126,122,185]],"0x0000000000000000000000000000000000000007":[[0,1,0,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,0,0,1,3,85,0,0,0,1,2,32,1,144],[0,0,0,74,0,0,193,61,0,0,0,32,2,16,3,112,0,0,0,0,3,2,4,59,0,0,0,0,4,1,4,59],[0,0,0,201,2,64,0,156,0,0,0,12,0,0,33,61,0,0,0,202,2,48,0,156,0,0,0,15,0,0,65,61],[0,0,0,0,1,0,4,20,0,0,0,0,1,16,4,32,0,0,0,0,1,0,3,103,0,0,0,0,2,67,1,160],[0,0,0,64,1,16,3,112,0,0,0,0,6,1,4,59,0,0,0,72,0,0,97,61,0,0,0,0,1,4,0,75],[0,0,0,203,33,64,0,209,0,0,0,1,2,32,192,57,0,0,0,204,81,64,0,209,0,0,0,202,81,16,0,209],[0,0,0,0,2,82,0,25,0,0,0,205,1,32,0,65,0,0,0,201,5,32,0,156,0,0,0,0,1,2,160,25],[0,0,0,0,82,17,0,170,0,0,0,1,5,80,192,57,0,0,0,206,114,32,0,209,0,0,0,202,114,32,0,209],[0,0,0,0,2,117,0,25,0,0,0,205,5,32,0,65,0,0,0,201,7,32,0,156,0,0,0,0,5,2,160,25],[0,0,0,0,117,21,0,170,0,0,0,1,7,112,192,57,0,0,0,0,2,3,0,75,0,0,0,203,130,48,0,209],[0,0,0,1,8,128,192,57,0,0,0,204,146,48,0,209,0,0,0,202,146,32,0,209,0,0,0,0,8,152,0,25],[0,0,0,205,2,128,0,65,0,0,0,201,9,128,0,156,0,0,0,0,2,8,160,25,0,0,0,0,152,34,0,170],[0,0,0,1,9,144,192,57,0,0,0,206,165,80,0,209,0,0,0,206,168,128,0,209,0,0,0,202,165,80,0,209],[0,0,0,0,5,167,0,25,0,0,0,202,135,128,0,209,0,0,0,0,7,137,0,25,0,0,0,205,8,80,0,65],[0,0,0,201,9,80,0,156,0,0,0,0,8,5,160,25,0,0,0,205,5,112,0,65,0,0,0,201,9,112,0,156],[0,0,0,0,5,7,160,25,0,0,0,207,7,0,0,65,0,0,0,208,9,0,0,65,0,0,0,209,10,128,0,156],[0,0,0,0,9,7,160,25,0,0,0,0,7,137,0,25,0,0,0,0,5,117,0,75,0,0,0,70,0,0,97,61],[0,0,0,0,5,0,4,20,0,0,0,0,5,80,4,32,0,0,0,0,5,6,0,75,0,0,0,79,0,0,193,61],[0,0,0,214,1,0,0,65,0,0,3,27,0,1,4,46,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67],[0,0,1,32,0,0,4,67,0,0,0,200,1,0,0,65,0,0,3,27,0,1,4,46,0,0,0,1,5,96,0,140],[0,0,0,85,0,0,193,61,0,0,0,0,0,64,4,53,0,0,0,32,0,48,4,63,0,0,0,214,1,0,0,65],[0,0,3,27,0,1,4,46,0,0,0,2,3,96,0,140,0,0,0,90,0,0,193,61,0,0,0,210,3,0,0,65],[3,26,2,172,0,0,4,15,0,0,2,89,0,0,1,61,0,0,0,210,8,0,0,65,0,0,0,0,3,0,0,25],[0,0,0,210,4,0,0,65,0,0,0,0,15,0,0,25,0,0,0,211,0,0,1,61,0,0,0,0,10,0,0,25],[0,0,0,0,152,34,0,170,0,0,0,206,184,128,0,209,0,0,0,202,184,128,0,209,0,0,0,1,11,176,192,57],[0,0,0,0,9,155,0,25,0,0,0,205,8,144,0,65,0,0,0,201,11,144,0,156,0,0,0,0,8,9,160,25],[0,0,0,1,9,128,2,16,0,0,0,2,11,128,2,16,0,0,0,211,12,176,0,65,0,0,0,201,9,144,0,156],[0,0,0,0,12,11,160,25,0,0,0,0,185,119,0,170,0,0,0,206,217,144,0,209,0,0,0,202,217,144,0,209],[0,0,0,1,13,208,192,57,0,0,0,0,11,189,0,25,0,0,0,0,151,39,0,170,0,0,0,206,215,112,0,209],[0,0,0,202,215,112,0,209,0,0,0,1,13,208,192,57,0,0,0,0,7,157,0,25,0,0,0,1,13,192,2,16],[0,0,0,211,9,208,0,65,0,0,0,201,12,192,0,156,0,0,0,0,9,13,160,25,0,0,0,205,12,176,0,65],[0,0,0,201,13,176,0,156,0,0,0,0,12,11,160,25,0,0,0,0,186,162,0,169,0,0,0,0,219,18,0,169],[0,0,0,0,10,173,0,25,0,0,0,0,33,33,0,170,0,0,0,206,33,16,0,209,0,0,0,202,33,16,0,209],[0,0,0,1,2,32,192,57,0,0,0,0,2,162,0,25,0,0,0,0,1,12,0,75,0,0,0,212,161,192,0,209],[0,0,0,1,10,160,192,57,0,0,0,47,177,192,0,201,0,0,0,202,177,16,0,209,0,0,0,0,10,186,0,25],[0,0,0,205,1,160,0,65,0,0,0,201,11,160,0,156,0,0,0,0,1,10,160,25,0,0,0,205,10,32,0,65],[0,0,0,201,11,32,0,156,0,0,0,0,10,2,160,25,0,0,0,1,2,16,2,16,0,0,0,205,11,32,0,65],[0,0,0,213,12,16,0,156,0,0,0,0,11,2,160,25,0,0,0,0,2,27,0,25,0,0,0,205,11,32,0,65],[0,0,0,201,12,32,0,156,0,0,0,0,11,2,160,25,0,0,0,0,2,184,0,73,0,0,0,202,11,32,0,65],[0,0,0,205,12,32,0,156,0,0,0,0,2,11,128,25,0,0,0,0,186,162,0,170,0,0,0,1,11,176,192,57],[0,0,0,0,8,129,0,25,0,0,0,205,12,128,0,65,0,0,0,201,13,128,0,156,0,0,0,0,12,8,160,25],[0,0,0,0,130,194,0,170,0,0,0,1,8,128,192,57,0,0,0,205,12,144,0,65,0,0,0,201,13,144,0,156],[0,0,0,0,12,9,160,25,0,0,0,0,145,28,0,170,0,0,0,1,9,144,192,57,0,0,0,205,13,112,0,65],[0,0,0,201,14,112,0,156,0,0,0,0,13,7,160,25,0,0,0,0,199,220,0,170,0,0,0,1,12,192,192,57],[0,0,0,206,218,160,0,209,0,0,0,202,218,160,0,209,0,0,0,0,10,219,0,25,0,0,0,1,11,160,2,16],[0,0,0,211,13,176,0,65,0,0,0,201,10,160,0,156,0,0,0,0,13,11,160,25,0,0,0,206,162,32,0,209],[0,0,0,206,161,16,0,209,0,0,0,206,167,112,0,209,0,0,0,202,162,32,0,209,0,0,0,0,2,168,0,25],[0,0,0,202,135,112,0,209,0,0,0,0,7,140,0,25,0,0,0,205,8,112,0,65,0,0,0,201,10,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,202,113,16,0,209,0,0,0,0,7,121,0,25,0,0,0,205,1,208,0,65],[0,0,0,201,9,208,0,156,0,0,0,0,1,13,160,25,0,0,0,205,9,32,0,65,0,0,0,201,10,32,0,156],[0,0,0,0,9,2,160,25,0,0,0,205,2,112,0,65,0,0,0,201,10,112,0,156,0,0,0,0,2,7,160,25],[0,0,0,0,7,41,0,25,0,0,0,205,2,112,0,65,0,0,0,201,9,112,0,156,0,0,0,0,2,7,160,25],[0,0,0,1,7,96,0,140,0,0,0,1,6,96,2,112,0,0,2,87,0,0,161,61,0,0,0,0,7,8,0,25],[0,0,0,1,8,96,1,144,0,0,0,95,0,0,97,61,0,0,0,0,8,3,0,75,0,0,1,114,0,0,97,61],[0,2,0,0,0,1,0,29,0,0,0,0,168,49,0,170,0,0,0,1,10,160,192,57,0,0,0,0,203,127,0,170],[0,0,0,1,12,192,192,57,0,0,0,0,237,116,0,170,0,0,0,1,14,224,192,57,0,0,0,0,1,15,0,25],[0,0,0,0,159,50,0,170,0,0,0,1,9,144,192,57,0,0,0,206,91,176,0,209,0,0,0,202,181,176,0,209],[0,0,0,0,5,188,0,25,0,0,0,206,184,128,0,209,0,0,0,205,12,80,0,65,0,0,0,201,11,80,0,156],[0,0,0,0,12,5,160,25,0,0,0,202,133,128,0,209,0,0,0,0,5,138,0,25,0,0,0,205,11,80,0,65],[0,0,0,201,8,80,0,156,0,0,0,0,11,5,160,25,0,0,0,206,133,208,0,209,0,0,0,202,133,80,0,209],[0,0,0,0,5,142,0,25,0,0,0,0,8,203,0,73,0,0,0,202,10,128,0,65,0,0,0,205,13,128,0,156],[0,0,0,0,8,10,128,25,0,0,0,205,10,80,0,65,0,0,0,201,13,80,0,156,0,0,0,0,10,5,160,25],[0,0,0,206,213,240,0,209,0,0,0,202,213,80,0,209,0,0,0,0,5,217,0,25,0,0,0,205,9,80,0,65],[0,0,0,201,13,80,0,156,0,0,0,0,9,5,160,25,0,0,0,0,10,169,0,73,0,0,0,202,5,160,0,65],[0,0,0,205,13,160,0,156,0,0,0,0,10,5,128,25,0,0,0,0,5,168,1,160,0,0,1,229,0,0,97,61],[0,0,0,0,67,55,0,170,0,0,0,1,4,64,192,57,0,0,0,0,213,170,0,170,0,0,0,1,13,208,192,57],[0,0,0,0,1,7,0,25,0,0,0,0,127,136,0,170,0,0,0,1,7,112,192,57,0,0,0,206,227,48,0,209],[0,0,0,202,227,48,0,209,0,0,0,0,4,228,0,25,0,0,0,205,3,64,0,65,0,0,0,201,14,64,0,156],[0,0,0,0,3,4,160,25,0,0,0,206,84,80,0,209,0,0,0,202,84,64,0,209,0,0,0,0,4,93,0,25],[0,0,0,205,5,64,0,65,0,0,0,201,13,64,0,156,0,0,0,0,5,4,160,25,0,0,0,0,222,53,0,170],[0,0,0,1,13,208,192,57,0,0,0,0,4,188,0,25,0,0,0,205,5,64,0,65,0,0,0,201,12,64,0,156],[0,0,0,0,5,4,160,25,0,0,0,206,196,240,0,209,0,0,0,202,196,64,0,209,0,0,0,0,4,199,0,25],[0,0,0,205,7,64,0,65,0,0,0,201,12,64,0,156,0,0,0,0,7,4,160,25,0,0,0,0,252,87,0,170],[0,0,0,1,15,240,192,57,0,0,0,0,91,183,0,170,0,0,0,1,5,80,192,57,0,1,0,0,64,135,0,174],[0,0,0,1,4,64,192,57,0,0,0,206,124,192,0,209,0,0,0,202,199,192,0,209,0,0,0,0,7,207,0,25],[0,0,0,205,12,112,0,65,0,0,0,201,15,112,0,156,0,0,0,0,12,7,160,25,0,0,0,206,231,224,0,209],[0,0,0,202,231,112,0,209,0,0,0,0,7,237,0,25,0,0,0,205,13,112,0,65,0,0,0,201,14,112,0,156],[0,0,0,0,13,7,160,25,0,0,0,0,7,205,0,73,0,0,0,206,203,176,0,209,0,0,0,202,12,112,0,65],[0,0,0,205,13,112,0,156,0,0,0,0,7,12,128,25,0,0,0,202,203,176,0,209,0,0,0,0,5,197,0,25],[0,0,0,205,11,80,0,65,0,0,0,201,12,80,0,156,0,0,0,0,11,5,160,25,0,0,0,0,5,123,0,73],[0,0,0,202,11,80,0,65,0,0,0,205,12,80,0,156,0,0,0,0,5,11,128,25,0,0,0,0,165,165,0,170],[0,0,0,1,10,160,192,57,0,0,0,0,135,135,0,170,0,0,0,1,8,128,192,57,0,0,0,1,11,0,0,41],[0,0,0,206,203,176,0,209,0,0,0,202,203,176,0,209,0,0,0,0,4,196,0,25,0,0,0,205,11,64,0,65],[0,0,0,201,12,64,0,156,0,0,0,0,11,4,160,25,0,0,0,0,148,155,0,170,0,0,0,1,9,144,192,57],[0,0,0,0,179,59,0,170,0,0,0,1,11,176,192,57,0,0,0,206,197,80,0,209,0,0,0,202,197,80,0,209],[0,0,0,0,5,202,0,25,0,0,0,206,167,112,0,209,0,0,0,206,164,64,0,209,0,0,0,202,164,64,0,209],[0,0,0,0,4,169,0,25,0,0,0,205,9,80,0,65,0,0,0,201,10,80,0,156,0,0,0,0,9,5,160,25],[0,0,0,202,117,112,0,209,0,0,0,0,5,120,0,25,0,0,0,205,7,64,0,65,0,0,0,201,8,64,0,156],[0,0,0,0,7,4,160,25,0,0,0,206,67,48,0,209,0,0,0,202,67,48,0,209,0,0,0,0,4,75,0,25],[0,0,0,205,3,64,0,65,0,0,0,201,8,64,0,156,0,0,0,0,3,4,160,25,0,0,0,0,4,121,0,73],[0,0,0,202,7,64,0,65,0,0,0,205,8,64,0,156,0,0,0,0,4,7,128,25,0,0,0,205,15,80,0,65],[0,0,0,201,7,80,0,156,0,0,0,0,7,1,0,25,0,0,0,0,15,5,160,25,0,0,0,0,10,0,0,25],[0,0,0,2,1,0,0,41,0,0,0,96,0,0,1,61,0,0,0,0,67,34,0,170,0,0,0,1,4,64,192,57],[0,0,0,206,83,48,0,209,0,0,0,202,83,48,0,209,0,0,0,0,3,84,0,25,0,0,0,205,4,48,0,65],[0,0,0,201,5,48,0,156,0,0,0,0,4,3,160,25,0,0,0,1,3,64,2,16,0,0,0,2,5,64,2,16],[0,0,0,211,9,80,0,65,0,0,0,201,3,48,0,156,0,0,0,0,9,5,160,25,0,0,0,0,186,119,0,170],[0,0,0,1,11,176,192,57,0,0,0,0,220,33,0,170,0,0,0,1,13,208,192,57,0,0,0,0,53,39,0,170],[0,0,0,1,3,48,192,57,0,0,0,1,14,144,2,16,0,0,0,211,8,224,0,65,0,0,0,201,9,144,0,156],[0,0,0,0,8,14,160,25,0,0,0,206,169,160,0,209,0,0,0,202,169,144,0,209,0,0,0,0,9,171,0,25],[0,0,0,205,10,144,0,65,0,0,0,201,11,144,0,156,0,0,0,0,10,9,160,25,0,0,0,0,9,10,0,75],[0,0,0,212,185,160,0,209,0,0,0,1,11,176,192,57,0,0,0,206,201,192,0,209,0,0,0,47,202,160,0,201],[0,0,0,202,202,160,0,209,0,0,0,0,10,203,0,25,0,0,0,202,185,144,0,209,0,0,0,0,11,189,0,25],[0,0,0,205,9,160,0,65,0,0,0,201,12,160,0,156,0,0,0,0,9,10,160,25,0,0,0,205,10,176,0,65],[0,0,0,201,12,176,0,156,0,0,0,0,10,11,160,25,0,0,0,1,11,144,2,16,0,0,0,205,12,176,0,65],[0,0,0,213,13,144,0,156,0,0,0,0,12,11,160,25,0,0,0,0,11,156,0,25,0,0,0,205,12,176,0,65],[0,0,0,201,13,176,0,156,0,0,0,0,12,11,160,25,0,0,0,0,11,196,0,73,0,0,0,202,12,176,0,65],[0,0,0,205,13,176,0,156,0,0,0,0,11,12,128,25,0,0,0,0,220,171,0,170,0,0,0,1,13,208,192,57],[0,0,0,0,4,73,0,25,0,0,0,205,10,64,0,65,0,0,0,201,14,64,0,156,0,0,0,0,10,4,160,25],[0,0,0,0,171,171,0,170,0,0,0,1,10,160,192,57,0,0,0,205,14,128,0,65,0,0,0,201,4,128,0,156],[0,0,0,0,14,8,160,25,0,0,0,0,72,233,0,170,0,0,0,1,4,64,192,57,0,0,0,206,149,80,0,209],[0,0,0,202,149,80,0,209,0,0,0,0,3,147,0,25,0,0,0,205,5,48,0,65,0,0,0,201,9,48,0,156],[0,0,0,0,5,3,160,25,0,0,0,0,83,94,0,170,0,0,0,1,5,80,192,57,0,0,0,206,201,192,0,209],[0,0,0,202,201,144,0,209,0,0,0,0,9,205,0,25,0,0,0,1,12,144,2,16,0,0,0,211,13,192,0,65],[0,0,0,201,9,144,0,156,0,0,0,0,13,12,160,25,0,0,0,206,185,176,0,209,0,0,0,206,139,128,0,209],[0,0,0,206,131,48,0,209,0,0,0,202,152,144,0,209,0,0,0,0,9,154,0,25,0,0,0,202,131,48,0,209],[0,0,0,0,3,133,0,25,0,0,0,205,8,48,0,65,0,0,0,201,5,48,0,156,0,0,0,0,8,3,160,25],[0,0,0,202,83,176,0,209,0,0,0,0,3,84,0,25,0,0,0,205,4,208,0,65,0,0,0,201,5,208,0,156],[0,0,0,0,4,13,160,25,0,0,0,205,5,144,0,65,0,0,0,201,10,144,0,156,0,0,0,0,5,9,160,25],[0,0,0,205,9,48,0,65,0,0,0,201,10,48,0,156,0,0,0,0,9,3,160,25,0,0,0,0,3,149,0,25],[0,0,0,205,9,48,0,65,0,0,0,201,5,48,0,156,0,0,0,0,9,3,160,25,0,0,0,0,15,1,0,25],[0,0,0,0,1,4,0,25,0,0,0,0,4,2,0,25,0,0,0,0,2,9,0,25,0,0,0,0,3,7,0,25],[0,0,0,208,0,0,1,61,0,0,0,0,9,1,0,25,0,0,0,0,33,68,0,170,0,0,0,1,2,32,192,57],[0,0,0,206,81,16,0,209,0,0,0,202,81,16,0,209,0,0,0,0,1,82,0,25,0,0,0,205,2,16,0,65],[0,0,0,201,5,16,0,156,0,0,0,0,2,1,160,25,0,0,0,1,1,32,2,16,0,0,0,2,5,32,2,16],[0,0,0,211,7,80,0,65,0,0,0,201,1,16,0,156,0,0,0,0,7,5,160,25,0,0,0,0,133,51,0,170],[0,0,0,1,8,128,192,57,0,0,0,0,169,73,0,170,0,0,0,1,10,160,192,57,0,0,0,0,19,52,0,170],[0,0,0,1,1,16,192,57,0,0,0,1,11,112,2,16,0,0,0,211,4,176,0,65,0,0,0,201,7,112,0,156],[0,0,0,0,4,11,160,25,0,0,0,206,117,80,0,209,0,0,0,202,117,80,0,209,0,0,0,0,5,120,0,25],[0,0,0,205,7,80,0,65,0,0,0,201,8,80,0,156,0,0,0,0,7,5,160,25,0,0,0,0,5,7,0,75],[0,0,0,212,133,112,0,209,0,0,0,1,8,128,192,57,0,0,0,206,149,144,0,209,0,0,0,47,151,112,0,201],[0,0,0,202,151,112,0,209,0,0,0,0,7,152,0,25,0,0,0,202,133,80,0,209,0,0,0,0,8,138,0,25],[0,0,0,205,5,112,0,65,0,0,0,201,9,112,0,156,0,0,0,0,5,7,160,25,0,0,0,205,7,128,0,65],[0,0,0,201,9,128,0,156,0,0,0,0,7,8,160,25,0,0,0,1,8,80,2,16,0,0,0,205,9,128,0,65],[0,0,0,213,10,80,0,156,0,0,0,0,9,8,160,25,0,0,0,0,8,89,0,25,0,0,0,205,9,128,0,65],[0,0,0,201,10,128,0,156,0,0,0,0,9,8,160,25,0,0,0,0,8,146,0,73,0,0,0,202,9,128,0,65],[0,0,0,205,10,128,0,156,0,0,0,0,8,9,128,25,0,0,0,0,169,120,0,170,0,0,0,1,10,160,192,57],[0,0,0,0,2,37,0,25,0,0,0,205,7,32,0,65,0,0,0,201,11,32,0,156,0,0,0,0,7,2,160,25],[0,0,0,0,120,120,0,170,0,0,0,1,7,112,192,57,0,0,0,205,11,64,0,65,0,0,0,201,2,64,0,156],[0,0,0,0,11,4,160,25,0,0,0,0,36,91,0,170,0,0,0,1,2,32,192,57,0,0,0,206,83,48,0,209],[0,0,0,202,83,48,0,209,0,0,0,0,1,81,0,25,0,0,0,205,3,16,0,65,0,0,0,201,5,16,0,156],[0,0,0,0,3,1,160,25,0,0,0,0,49,59,0,170,0,0,0,1,3,48,192,57,0,0,0,206,149,144,0,209],[0,0,0,202,149,80,0,209,0,0,0,0,5,154,0,25,0,0,0,1,9,80,2,16,0,0,0,211,10,144,0,65],[0,0,0,201,5,80,0,156,0,0,0,0,10,9,160,25,0,0,0,206,133,128,0,209,0,0,0,206,132,64,0,209],[0,0,0,206,129,16,0,209,0,0,0,202,133,80,0,209,0,0,0,0,5,135,0,25,0,0,0,202,113,16,0,209],[0,0,0,0,1,115,0,25,0,0,0,205,8,16,0,65,0,0,0,201,3,16,0,156,0,0,0,0,8,1,160,25],[0,0,0,202,49,64,0,209,0,0,0,0,1,50,0,25,0,0,0,205,15,160,0,65,0,0,0,201,2,160,0,156],[0,0,0,0,15,10,160,25,0,0,0,205,2,80,0,65,0,0,0,201,3,80,0,156,0,0,0,0,2,5,160,25],[0,0,0,205,3,16,0,65,0,0,0,201,4,16,0,156,0,0,0,0,3,1,160,25,0,0,0,0,1,50,0,25],[0,0,0,205,4,16,0,65,0,0,0,201,2,16,0,156,0,0,0,0,4,1,160,25,0,0,0,0,1,15,0,25],[0,0,0,0,2,4,0,25,0,0,0,0,3,8,0,25,0,0,0,208,0,0,1,61,0,0,0,0,1,15,0,25],[0,0,0,0,2,4,0,25,3,26,2,108,0,0,4,15,0,2,0,0,0,2,0,29,3,26,2,100,0,0,4,15],[0,1,0,0,0,1,0,29,0,0,0,2,1,0,0,41,3,26,2,100,0,0,4,15,0,0,0,1,2,0,0,41],[0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,214,1,0,0,65,0,0,3,27,0,1,4,46],[0,0,0,0,2,1,0,75,0,0,0,206,33,16,0,209,0,0,0,202,33,16,0,209,0,0,0,1,2,32,192,57],[0,0,0,205,1,32,0,65,0,0,0,201,3,32,0,156,0,0,0,0,1,2,160,25,0,0,0,0,0,1,4,45],[0,0,0,0,4,3,0,75,0,0,0,0,5,0,0,25,0,0,0,0,4,0,0,25,0,0,2,169,0,0,97,61],[0,0,0,203,4,0,0,65,0,0,0,1,5,48,0,140,0,0,2,153,0,0,97,61,0,0,0,202,5,0,0,65],[0,0,0,203,4,0,0,65,0,0,0,0,6,0,0,25,0,0,0,1,7,48,1,144,0,0,2,126,0,0,193,61],[0,0,0,1,7,64,1,144,0,0,0,202,4,64,192,65,0,0,0,2,7,48,1,144,0,0,0,1,3,48,2,112],[0,0,0,1,4,64,2,112,0,0,2,120,0,0,97,61,0,0,0,1,7,80,1,144,0,0,2,134,0,0,193,61],[0,0,0,1,7,96,1,144,0,0,0,202,6,96,192,65,0,0,0,2,7,80,1,144,0,0,0,1,5,80,2,112],[0,0,0,1,6,96,2,112,0,0,2,128,0,0,97,61,0,0,0,0,7,53,0,75,0,0,2,142,0,0,161,61],[0,0,0,202,7,96,0,65,0,0,0,0,8,70,0,75,0,0,0,0,7,6,128,25,0,0,0,0,6,71,0,73],[0,0,0,0,5,53,0,73,0,0,2,147,0,0,1,61,0,0,0,202,7,64,0,65,0,0,0,0,8,100,0,75],[0,0,0,0,7,4,128,25,0,0,0,0,4,103,0,73,0,0,0,0,3,83,0,73,0,0,0,1,7,48,0,140],[0,0,2,151,0,0,97,61,0,0,0,1,7,80,0,140,0,0,2,118,0,0,193,61,0,0,0,1,3,48,0,140],[0,0,0,0,4,6,192,25,0,0,0,0,49,20,0,170,0,0,0,1,3,48,192,57,0,0,0,0,66,36,0,170],[0,0,0,1,4,64,192,57,0,0,0,206,82,32,0,209,0,0,0,202,82,32,0,209,0,0,0,0,2,84,0,25],[0,0,0,205,4,32,0,65,0,0,0,201,5,32,0,156,0,0,0,0,4,2,160,25,0,0,0,206,33,16,0,209],[0,0,0,202,33,16,0,209,0,0,0,0,1,35,0,25,0,0,0,205,5,16,0,65,0,0,0,201,2,16,0,156],[0,0,0,0,5,1,160,25,0,0,0,0,1,5,0,25,0,0,0,0,2,4,0,25,0,0,0,0,0,1,4,45],[0,0,0,0,84,34,0,170,0,0,0,1,5,80,192,57,0,0,0,206,100,64,0,209,0,0,0,202,100,64,0,209],[0,0,0,0,5,101,0,25,0,0,0,205,4,80,0,65,0,0,0,201,6,80,0,156,0,0,0,0,4,5,160,25],[0,0,0,1,5,64,2,16,0,0,0,2,6,64,2,16,0,0,0,211,7,96,0,65,0,0,0,201,5,80,0,156],[0,0,0,0,7,6,160,25,0,0,0,0,101,51,0,170,0,0,0,1,6,96,192,57,0,0,0,0,152,18,0,170],[0,0,0,1,9,144,192,57,0,0,0,0,18,35,0,170,0,0,0,1,1,16,192,57,0,0,0,1,10,112,2,16],[0,0,0,211,3,160,0,65,0,0,0,201,7,112,0,156,0,0,0,0,3,10,160,25,0,0,0,206,117,80,0,209],[0,0,0,202,117,80,0,209,0,0,0,0,5,118,0,25,0,0,0,205,6,80,0,65,0,0,0,201,7,80,0,156],[0,0,0,0,6,5,160,25,0,0,0,0,5,6,0,75,0,0,0,212,117,96,0,209,0,0,0,1,7,112,192,57],[0,0,0,206,133,128,0,209,0,0,0,47,134,96,0,201,0,0,0,202,134,96,0,209,0,0,0,0,6,135,0,25],[0,0,0,202,117,80,0,209,0,0,0,0,7,121,0,25,0,0,0,205,5,96,0,65,0,0,0,201,8,96,0,156],[0,0,0,0,5,6,160,25,0,0,0,205,6,112,0,65,0,0,0,201,8,112,0,156,0,0,0,0,6,7,160,25],[0,0,0,1,7,80,2,16,0,0,0,205,8,112,0,65,0,0,0,213,9,80,0,156,0,0,0,0,8,7,160,25],[0,0,0,0,7,88,0,25,0,0,0,205,8,112,0,65,0,0,0,201,9,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,0,7,132,0,73,0,0,0,202,8,112,0,65,0,0,0,205,9,112,0,156,0,0,0,0,7,8,128,25],[0,0,0,0,152,103,0,170,0,0,0,1,9,144,192,57,0,0,0,0,4,69,0,25,0,0,0,205,6,64,0,65],[0,0,0,201,10,64,0,156,0,0,0,0,6,4,160,25,0,0,0,0,103,103,0,170,0,0,0,1,6,96,192,57],[0,0,0,205,10,48,0,65,0,0,0,201,4,48,0,156,0,0,0,0,10,3,160,25,0,0,0,0,67,165,0,170],[0,0,0,1,4,64,192,57,0,0,0,206,82,32,0,209,0,0,0,202,82,32,0,209,0,0,0,0,1,81,0,25],[0,0,0,205,2,16,0,65,0,0,0,201,5,16,0,156,0,0,0,0,2,1,160,25,0,0,0,0,33,42,0,170],[0,0,0,1,2,32,192,57,0,0,0,206,133,128,0,209,0,0,0,202,133,80,0,209,0,0,0,0,5,137,0,25],[0,0,0,1,8,80,2,16,0,0,0,211,9,128,0,65,0,0,0,201,5,80,0,156,0,0,0,0,9,8,160,25],[0,0,0,206,117,112,0,209,0,0,0,206,55,48,0,209,0,0,0,206,49,16,0,209,0,0,0,202,83,80,0,209],[0,0,0,0,5,86,0,25,0,0,0,202,49,16,0,209,0,0,0,0,1,50,0,25,0,0,0,205,3,16,0,65],[0,0,0,201,2,16,0,156,0,0,0,0,3,1,160,25,0,0,0,202,33,112,0,209,0,0,0,0,2,36,0,25],[0,0,0,205,1,144,0,65,0,0,0,201,4,144,0,156,0,0,0,0,1,9,160,25,0,0,0,205,4,80,0,65],[0,0,0,201,6,80,0,156,0,0,0,0,4,5,160,25,0,0,0,205,5,32,0,65,0,0,0,201,6,32,0,156],[0,0,0,0,5,2,160,25,0,0,0,0,4,84,0,25,0,0,0,205,2,64,0,65,0,0,0,201,5,64,0,156],[0,0,0,0,2,4,160,25,0,0,0,0,0,1,4,45,0,0,3,26,0,0,4,50,0,0,3,27,0,1,4,46],[0,0,3,28,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,70],[48,100,78,114,225,49,160,41,184,80,69,182,129,129,88,93,151,129,106,145,104,113,202,141,60,32,140,22,216,124,253,71],[6,216,159,113,202,184,53,31,71,171,30,255,10,65,127,246,181,231,25,17,212,69,1,251,243,44,252,91,83,138,250,137],[74,71,70,38,35,160,74,122,176,116,165,134,128,115,1,58,233,101,225,118,124,212,192,134,243,174,216,161,155,249,14,81],[207,155,177,141,30,206,95,214,71,175,186,73,126,126,167,162,104,126,149,110,151,142,53,114,195,223,115,233,39,131,2,185],[245,122,34,183,145,136,140,107,216,175,203,208,24,51,218,128,158,222,125,101,30,202,106,201,135,210,7,130,228,134,99,137],[42,31,103,68,206,23,157,142,51,75,234,78,105,107,210,132,31,106,193,122,225,85,33,185,122,23,202,169,80,173,40,215],[249,187,24,209,236,229,253,100,122,251,164,151,231,234,122,38,135,233,86,233,120,227,87,44,61,247,62,146,120,48,43,144],[6,68,231,46,19,26,2,155,133,4,91,104,24,21,133,217,120,22,169,22,135,28,168,211,194,8,193,109,135,207,212,111],[14,10,119,193,154,7,223,47,102,110,163,111,120,121,70,44,10,120,235,40,245,199,11,61,211,93,67,141,197,143,13,157],[159,55,99,26,61,156,191,172,143,95,116,146,252,253,79,68,208,253,42,221,47,28,106,229,135,190,231,210,79,6,5,114],[29,149,152,232,167,227,152,87,41,67,51,126,57,64,198,209,47,61,111,77,211,27,208,17,246,6,71,206,65,13,127,247],[24,50,39,57,112,152,208,20,220,40,34,219,64,192,172,46,203,192,181,72,180,56,229,70,158,16,70,11,108,62,126,163],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[136,210,215,145,1,9,72,102,245,6,226,206,231,74,222,121,140,90,74,182,159,125,137,7,252,66,94,207,167,28,22,58]],"0x0000000000000000000000000000000000000002":[[0,0,0,1,2,32,1,144,0,0,0,51,0,0,193,61,0,0,0,0,2,1,0,25,0,0,0,96,3,32,2,112],[0,0,0,31,4,48,1,143,0,0,0,17,2,48,1,151,0,0,0,5,5,32,2,114,0,0,0,16,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,0,9,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,0,30,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,5,80,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,81,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,18,1,0,0,65,0,0,0,0,0,18,4,53],[0,0,0,8,1,48,0,57,0,0,0,63,1,16,1,143,0,0,0,0,1,18,0,73,0,0,0,195,2,32,2,16],[0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,72,1,16,0,57,0,0,0,27,2,16,2,16],[0,0,0,19,2,32,1,151,0,0,0,6,1,16,2,112,0,0,0,192,3,16,2,16,0,0,0,0,2,50,1,159],[0,0,0,20,2,32,1,199,0,0,0,7,49,16,0,201,0,0,0,0,1,18,4,32,0,0,0,0,1,1,0,75],[0,0,0,56,0,0,193,61,0,0,0,0,1,0,0,25,0,0,0,60,0,1,4,48,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,16,1,0,0,65,0,0,0,59,0,1,4,46],[0,0,0,21,1,0,0,65,0,0,0,59,0,1,4,46,0,0,0,58,0,0,4,50,0,0,0,59,0,1,4,46],[0,0,0,60,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,254,255,255,255,255,255,255,255,255,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[163,6,139,9,248,74,233,86,156,89,18,239,176,49,25,58,139,131,161,16,140,157,193,139,157,74,170,24,136,162,125,123]],"0x0000000000000000000000000000000000008009":[[0,2,0,0,0,0,0,2,0,6,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,6,1,0,25],[0,0,0,96,6,96,2,112,0,0,0,75,0,96,1,157,0,0,0,128,7,0,0,57,0,0,0,64,0,112,4,63],[0,0,0,75,9,96,1,151,0,0,0,0,8,0,4,22,0,0,0,1,7,32,1,144,0,0,0,31,0,0,193,61],[0,0,0,0,7,8,0,75,0,0,0,105,0,0,193,61,0,0,0,2,2,32,1,144,0,0,0,38,0,0,193,61],[0,0,0,0,2,0,4,17,0,0,0,77,2,32,0,156,0,0,0,38,0,0,65,61,0,0,0,90,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,94,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,95,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,0,96,1,0,0,65,0,0,1,42,0,1,4,48,0,0,0,0,1,8,0,75],[0,0,0,105,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,76,1,0,0,65,0,0,1,41,0,1,4,46,0,0,0,78,2,64,1,151,0,0,0,0,4,0,4,16],[0,0,0,0,4,66,0,75,0,0,0,52,0,0,193,61,0,0,0,90,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,30,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,0,92,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,93,1,0,0,65,0,0,1,42,0,1,4,48],[0,0,0,0,4,3,0,75,0,0,0,0,8,0,4,17,0,0,0,0,7,9,0,25,0,0,0,64,0,0,193,61],[0,0,0,0,0,3,4,23,0,0,0,0,3,0,4,20,0,0,0,0,4,151,0,75,0,0,0,107,0,0,129,61],[0,0,0,87,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,0,255,0,0,1,61],[0,3,0,0,0,9,0,29,0,5,0,0,0,5,0,29,0,6,0,0,0,6,0,29,0,0,0,79,1,0,0,65],[0,0,0,160,0,16,4,63,0,1,0,0,0,8,0,29,0,0,0,78,1,128,1,151,0,0,0,164,0,16,4,63],[0,2,0,0,0,2,0,29,0,0,0,196,0,32,4,63,0,4,0,0,0,3,0,29,0,0,0,228,0,48,4,63],[0,0,0,100,1,0,0,57,0,0,0,128,0,16,4,63,0,0,1,32,1,0,0,57,0,0,0,64,0,16,4,63],[0,0,0,75,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,75,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,80,1,16,1,199,0,0,128,10,2,0,0,57,1,40,1,29,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,75,5,48,1,152,0,0,0,127,0,0,193,61],[0,0,0,1,1,32,1,144,0,0,0,6,6,0,0,41,0,0,0,5,5,0,0,41,0,0,0,4,3,0,0,41],[0,0,0,3,9,0,0,41,0,0,0,105,0,0,97,61,0,0,0,83,1,48,0,156,0,0,0,2,2,0,0,41],[0,0,0,1,8,0,0,41,0,0,0,109,0,0,33,61,0,0,0,1,1,0,3,103,0,0,0,0,7,0,0,49],[0,0,0,56,0,0,1,61,0,0,0,0,1,0,0,25,0,0,1,42,0,1,4,48,0,0,0,75,4,48,0,156],[0,0,0,168,0,0,161,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,89,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,90,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,75,2,0,0,65,0,0,0,75,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,0,91,1,16,1,199,0,0,1,42,0,1,4,48,0,0,0,63,3,80,0,57],[0,0,0,81,3,48,1,151,0,0,0,64,4,0,4,61,0,0,0,0,3,52,0,25,0,0,0,0,6,67,0,75],[0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57,0,0,0,82,7,48,0,156,0,0,0,252,0,0,33,61],[0,0,0,1,6,96,1,144,0,0,0,252,0,0,193,61,0,0,0,64,0,48,4,63,0,0,0,31,3,80,1,143],[0,0,0,0,4,84,4,54,0,0,0,5,5,80,2,114,0,0,0,152,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,0,144,0,0,65,61],[0,0,0,0,6,3,0,75,0,0,0,92,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,4,84,0,25,0,0,0,3,3,48,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,20,4,53,0,0,0,92,0,0,1,61],[0,0,0,1,4,80,1,144,0,0,0,84,4,0,0,65,0,0,0,85,5,0,0,65,0,0,0,0,5,4,192,25],[0,0,0,192,3,48,2,16,0,0,0,86,3,48,1,151,0,0,0,0,3,83,1,159,0,0,0,0,4,103,0,73],[0,0,0,75,4,64,1,151,0,0,0,0,1,65,3,223,0,0,0,0,1,49,3,175,0,0,0,78,13,128,1,151],[1,40,1,34,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,0,75,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,1,2,0,0,97,61,0,0,0,63,2,48,0,57,0,0,0,81,4,32,1,151],[0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,0,82,6,64,0,156,0,0,0,252,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,0,252,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57],[0,0,0,5,5,80,2,114,0,0,0,213,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,0,205,0,0,65,61,0,0,0,0,5,0,0,75,0,0,0,215,0,0,97,61,0,0,0,31,5,48,1,143],[0,0,0,5,3,48,2,114,0,0,0,227,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,0,219,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,0,242,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,0,1,2,4,51,0,0,0,75,2,0,0,65],[0,0,0,75,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,75,3,64,0,156,0,0,0,0,4,2,128,25],[0,0,0,64,2,64,2,16,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,1,41,0,1,4,46],[0,0,0,87,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63],[0,0,0,88,1,0,0,65,0,0,1,42,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,1,13,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,1,6,0,0,65,61,0,0,0,0,5,4,0,75,0,0,1,27,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,1,42,0,1,4,48,0,0,1,32,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,0,0,15,13,0,25,0,0,1,38,0,33,4,41],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,1,40,0,0,4,50,0,0,1,41,0,1,4,46,0,0,1,42,0,1,4,48,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[87,153,82,252,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,160,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[77,115,103,86,97,108,117,101,83,105,109,117,108,97,116,111,114,32,99,97,108,108,115,32,105,116,115,101,108,102,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,115,121,115,116,101,109,32,99,97,108,108,32],[102,108,97,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[104,86,206,249,159,64,233,200,187,185,162,103,175,77,178,97,168,231,132,34,191,2,15,56,177,244,203,85,226,83,209,29]],"0x000000000000000000000000000000000000800b":[[0,1,0,0,0,0,0,2,0,6,0,0,0,0,0,2,0,0,0,0,0,1,3,85,0,0,0,128,4,0,0,57],[0,0,0,64,0,64,4,63,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,1,24,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,0,33,0,0,193,61,0,0,0,4,2,48,0,140,0,0,3,150,0,0,65,61],[0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112,0,0,1,28,5,32,0,156,0,0,0,52,0,0,33,61],[0,0,1,46,5,32,0,156,0,0,0,67,0,0,161,61,0,0,1,47,4,32,0,156,0,0,0,123,0,0,161,61],[0,0,1,48,4,32,0,156,0,0,0,200,0,0,33,61,0,0,1,51,1,32,0,156,0,0,1,16,0,0,97,61],[0,0,1,52,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,1,12,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,64,1,16,1,151],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,1,24,1,0,0,65,0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,4,1,0,0,57],[0,0,0,0,2,1,4,26,0,0,1,25,2,32,1,151,0,0,128,1,2,32,1,191,0,0,0,0,0,33,4,27],[0,0,1,26,1,0,0,65,0,0,0,5,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,1,27,1,0,0,65,0,0,4,90,0,1,4,46],[0,0,1,29,4,32,0,156,0,0,0,99,0,0,161,61,0,0,1,30,4,32,0,156,0,0,0,134,0,0,161,61],[0,0,1,31,4,32,0,156,0,0,0,248,0,0,33,61,0,0,1,34,1,32,0,156,0,0,0,62,0,0,97,61],[0,0,1,35,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,4,89,4,24,0,0,4,15,0,0,0,111,0,0,1,61,0,0,1,56,5,32,0,156],[0,0,0,156,0,0,33,61,0,0,1,60,5,32,0,156,0,0,1,21,0,0,97,61,0,0,1,61,5,32,0,156],[0,0,1,87,0,0,97,61,0,0,1,62,2,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140],[0,0,3,150,0,0,65,61,0,0,0,0,2,0,4,17,0,0,128,1,2,32,0,140,0,0,2,22,0,0,193,61],[0,0,0,10,2,0,0,57,0,6,0,0,0,2,0,29,0,0,0,0,2,2,4,26,0,0,0,160,0,32,4,63],[0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,192,0,16,4,63,0,0,0,64,2,0,0,57],[0,0,0,128,0,32,4,63,0,0,0,224,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,160,1,0,0,57],[4,89,4,62,0,0,4,15,0,0,0,6,2,0,0,41,0,0,1,227,0,0,1,61,0,0,1,39,4,32,0,156],[0,0,0,179,0,0,33,61,0,0,1,43,4,32,0,156,0,0,1,1,0,0,97,61,0,0,1,44,1,32,0,156],[0,0,1,143,0,0,97,61,0,0,1,45,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,4,89,4,43,0,0,4,15,0,0,1,64,2,32,1,151],[0,0,0,64,3,0,4,61,0,0,0,32,4,48,0,57,0,0,0,0,0,36,4,53,0,0,1,64,1,16,1,151],[0,0,0,0,0,19,4,53,0,0,1,24,1,0,0,65,0,0,1,24,2,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,64,1,48,2,16,0,0,1,65,1,16,1,199,0,0,4,90,0,1,4,46,0,0,1,53,1,32,0,156],[0,0,1,150,0,0,97,61,0,0,1,54,1,32,0,156,0,0,1,162,0,0,97,61,0,0,1,55,1,32,0,156],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,6,1,0,0,57,0,0,1,199,0,0,1,61,0,0,1,36,4,32,0,156,0,0,1,169,0,0,97,61],[0,0,1,37,4,32,0,156,0,0,1,174,0,0,97,61,0,0,1,38,1,32,0,156,0,0,3,150,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,4,1,48,0,138],[0,0,0,32,1,16,0,140,0,0,3,150,0,0,65,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,4,89,3,248,0,0,4,15,0,0,0,4,1,0,0,57],[0,0,0,0,1,16,3,103,0,0,0,0,1,1,4,59,0,0,0,2,2,0,0,57,0,0,1,227,0,0,1,61],[0,0,1,57,1,32,0,156,0,0,1,195,0,0,97,61,0,0,1,58,1,32,0,156,0,0,1,201,0,0,97,61],[0,0,1,59,1,32,0,156,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,2,22,0,0,193,61],[0,0,1,14,1,0,0,57,0,0,0,0,2,1,4,26,0,0,255,255,3,32,1,143,0,0,255,255,4,48,0,140],[0,0,2,32,0,0,193,61,0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48,0,0,1,40,1,32,0,156],[0,0,1,230,0,0,97,61,0,0,1,41,1,32,0,156,0,0,1,237,0,0,97,61,0,0,1,42,1,32,0,156],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[4,89,4,24,0,0,4,15,0,0,1,64,2,32,1,151,0,0,0,128,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,0,64,2,0,4,61,0,0,0,0,0,18,4,53,0,0,1,24,1,0,0,65,0,0,1,24,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,1,67,1,16,1,199,0,0,4,90,0,1,4,46],[0,0,1,49,4,32,0,156,0,0,1,244,0,0,97,61,0,0,1,50,2,32,0,156,0,0,3,150,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,3,150,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,1,12,2,0,0,57,0,0,0,0,2,2,4,26,0,0,0,192,3,0,0,57,0,0,0,64,0,48,4,63],[0,0,0,128,6,32,2,112,0,0,1,13,2,0,0,57,0,0,0,0,3,2,4,26,0,0,1,64,5,48,1,151],[0,0,0,128,0,80,4,63,0,0,0,128,2,48,2,112,0,0,0,160,0,32,4,63,0,0,0,0,4,22,0,75],[0,0,0,0,4,0,0,25,0,0,2,68,0,0,161,61,0,0,0,0,4,22,0,73,0,0,1,1,4,64,0,140],[0,0,0,0,4,0,0,25,0,0,2,68,0,0,129,61,0,0,0,0,4,81,0,75,0,0,2,38,0,0,129,61],[0,0,0,0,0,16,4,53,0,0,0,8,1,0,0,57,0,0,0,32,0,16,4,63,0,0,1,24,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,1,70,1,16,1,199,0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,3,150,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,4,1,4,26,0,0,2,68,0,0,1,61],[0,0,1,32,4,32,0,156,0,0,1,1,0,0,97,61,0,0,1,33,1,32,0,156,0,0,3,150,0,0,193,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,2,1,0,0,57],[0,0,1,199,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,3,150,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,1,1,4,59,0,0,0,0,0,16,4,53,0,0,0,8,1,0,0,57,0,0,0,32,0,16,4,63],[0,0,0,64,2,0,0,57,0,0,0,0,1,0,0,25,4,89,4,62,0,0,4,15,0,0,1,199,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,3,1,0,0,57],[0,0,1,199,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,128,2,32,0,140,0,0,3,150,0,0,65,61,0,0,0,4,2,16,3,112],[0,0,0,0,3,2,4,59,0,0,0,36,2,16,3,112,0,0,0,0,4,2,4,59,0,0,1,64,2,64,0,156],[0,0,3,150,0,0,33,61,0,0,0,68,1,16,3,112,0,0,0,0,5,1,4,59,0,0,1,64,1,80,0,156],[0,0,3,150,0,0,33,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,2,22,0,0,193,61],[0,0,0,192,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,7,6,0,0,57,0,0,0,0,1,6,4,26],[0,0,1,64,2,16,1,151,0,0,0,128,0,32,4,63,0,0,0,128,1,16,2,112,0,0,0,160,0,16,4,63],[0,0,0,0,2,36,0,75,0,0,2,76,0,0,161,61,0,0,1,64,2,16,0,156,0,0,0,173,0,0,97,61],[0,0,0,1,2,16,0,57,0,0,0,0,2,82,0,75,0,0,2,85,0,0,193,61,0,3,0,0,0,6,0,29],[0,4,0,0,0,5,0,29,0,6,0,0,0,3,0,29,0,0,0,9,2,0,0,57,0,0,0,0,2,2,4,26],[0,0,1,64,2,32,1,151,0,5,0,0,0,4,0,29,0,0,0,0,2,36,0,75,0,0,2,97,0,0,161,61],[0,0,0,0,0,16,4,53,0,0,0,8,1,0,0,57,0,0,0,32,0,16,4,63,0,0,1,24,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,1,70,1,16,1,199,0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,6,2,0,0,41,0,0,3,150,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,33,4,27],[0,0,0,64,1,0,4,61,0,0,1,94,2,16,0,156,0,0,3,17,0,0,161,61,0,0,1,123,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,176,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,160,2,32,0,140],[0,0,3,150,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,6,2,4,59,0,0,1,64,2,96,0,156],[0,0,3,150,0,0,33,61,0,0,0,36,2,16,3,112,0,0,0,0,5,2,4,59,0,0,1,64,2,80,0,156],[0,0,3,150,0,0,33,61,0,0,0,68,2,16,3,112,0,0,0,0,7,2,4,59,0,0,0,100,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,0,0,3,2,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,192,57],[0,0,0,0,3,50,0,75,0,0,3,150,0,0,193,61,0,0,0,132,1,16,3,112,0,0,0,0,3,1,4,59],[0,0,1,64,1,48,0,156,0,0,3,150,0,0,33,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140],[0,0,2,22,0,0,193,61,0,0,0,0,1,2,0,75,0,6,0,0,0,3,0,29,0,4,0,0,0,7,0,29],[0,0,2,126,0,0,97,61,0,0,0,7,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,64,1,16,1,151],[0,0,0,0,3,5,0,25,0,0,0,0,1,21,0,75,0,0,2,111,0,0,129,61,0,0,1,71,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,97,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,79,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,80,1,0,0,65],[0,0,0,228,0,16,4,63,0,0,1,81,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,82,1,0,0,65],[0,0,1,36,0,16,4,63,0,0,1,83,1,0,0,65,0,0,4,91,0,1,4,48,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,1,14,1,0,0,57,0,0,0,0,1,1,4,26],[0,0,255,255,1,16,1,143,0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,4,89,3,248,0,0,4,15,0,0,1,14,1,0,0,57,0,0,0,0,2,1,4,26],[0,0,1,75,2,32,1,151,0,0,2,35,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,1,12,1,0,0,57,0,0,0,0,1,1,4,26,0,0,0,128,1,16,2,112],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,1,0,0,57,0,0,1,234,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,3,150,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,3,150,0,0,65,61],[0,0,0,4,1,16,3,112,0,0,0,0,2,1,4,59,0,0,1,66,1,32,0,156,0,0,3,150,0,0,33,61],[0,0,0,0,1,0,4,17,0,0,128,1,1,16,0,140,0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57],[0,6,0,0,0,2,0,29,4,89,3,248,0,0,4,15,0,0,0,1,1,0,0,57,0,0,0,0,2,1,4,26],[0,0,1,25,2,32,1,151,0,0,0,6,2,32,1,175,0,0,2,35,0,0,1,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,5,1,0,0,57,0,0,0,0,1,1,4,26],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,4,1,48,0,138,0,0,0,96,1,16,0,140,0,0,3,150,0,0,65,61,0,0,0,0,1,0,4,17],[0,0,128,1,1,16,0,140,0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,4,89,3,248,0,0,4,15],[0,0,0,64,1,0,4,61,4,89,4,13,0,0,4,15,0,0,0,0,1,0,3,103,0,0,0,36,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,0,128,2,32,2,16,0,0,0,4,3,16,3,112,0,0,0,0,3,3,4,59],[0,0,1,64,3,48,1,151,0,0,0,0,2,35,1,159,0,0,0,7,3,0,0,57,0,0,0,0,0,35,4,27],[0,0,0,68,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27],[0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,3,150,0,0,193,61,0,0,0,1,1,0,0,57,0,0,0,0,1,1,4,26,0,0,1,66,1,16,1,151],[0,0,1,241,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61],[0,0,0,0,1,0,4,26,0,0,0,128,0,16,4,63,0,0,1,63,1,0,0,65,0,0,4,90,0,1,4,46],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,3,150,0,0,193,61,0,0,0,0,1,0,4,17],[0,0,128,1,1,16,0,140,0,0,2,22,0,0,193,61,0,0,0,7,1,0,0,57,0,0,0,0,3,1,4,26],[0,0,1,64,1,48,1,151,0,0,0,128,0,16,4,63,0,0,0,128,2,48,2,112,0,0,0,160,0,32,4,63],[0,0,1,0,2,0,0,57,0,0,0,64,0,32,4,63,0,0,0,9,2,0,0,57,0,0,0,0,4,2,4,26],[0,0,1,64,2,64,1,151,0,0,0,192,0,32,4,63,0,0,0,128,4,64,2,112,0,0,0,224,0,64,4,63],[0,0,1,64,3,48,0,156,0,0,2,46,0,0,33,61,0,0,1,71,1,0,0,65,0,0,1,0,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,1,4,0,16,4,63,0,0,0,47,1,0,0,57,0,0,1,36,0,16,4,63],[0,0,1,72,1,0,0,65,0,0,1,68,0,16,4,63,0,0,1,73,1,0,0,65,0,0,1,100,0,16,4,63],[0,0,1,74,1,0,0,65,0,0,4,91,0,1,4,48,0,0,1,71,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,114,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,115,1,0,0,65,0,0,4,91,0,1,4,48],[0,0,1,75,2,32,1,151,0,0,0,1,3,48,0,57,0,0,0,0,2,35,1,159,0,0,0,0,0,33,4,27],[0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46,0,0,1,68,3,48,0,156,0,0,2,52,0,0,65,61],[0,0,0,0,2,33,0,75,0,0,2,52,0,0,65,61,0,0,1,1,33,16,1,26,0,0,0,11,1,32,0,57],[0,0,0,0,4,1,4,26,0,0,2,68,0,0,1,61,0,0,0,128,1,16,2,16,0,0,0,0,1,18,1,159],[0,0,0,3,2,0,0,57,0,0,0,0,0,18,4,28,0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46],[0,0,0,224,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,192,0,16,4,63,0,0,1,0,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,1,24,1,0,0,65,0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,1,69,1,16,1,199,0,0,128,16,2,0,0,57],[4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144,0,0,3,150,0,0,97,61,0,0,0,0,4,1,4,59],[0,0,0,64,1,0,4,61,0,0,0,0,0,65,4,53,0,0,1,24,2,0,0,65,0,0,1,24,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,1,67,1,16,1,199,0,0,4,90,0,1,4,46],[0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63],[0,0,0,228,0,16,4,63,0,0,1,116,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,85,1,0,0,65],[0,0,4,91,0,1,4,48,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,196,0,16,4,63,0,0,0,40,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,117,1,0,0,65],[0,0,1,4,0,16,4,63,0,0,1,118,1,0,0,65,0,0,1,36,0,16,4,63,0,0,1,97,1,0,0,65],[0,0,4,91,0,1,4,48,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,196,0,16,4,63,0,0,0,83,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,119,1,0,0,65],[0,0,1,4,0,16,4,63,0,0,1,120,1,0,0,65,0,0,1,36,0,16,4,63,0,0,1,121,1,0,0,65],[0,0,1,68,0,16,4,63,0,0,1,122,1,0,0,65,0,0,4,91,0,1,4,48,0,0,0,6,1,0,0,107],[0,0,0,0,5,3,0,25,0,0,2,126,0,0,193,61,0,0,1,71,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,63,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,76,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,77,1,0,0,65,0,0,0,228,0,16,4,63],[0,0,1,78,1,0,0,65,0,0,4,91,0,1,4,48,0,2,0,0,0,5,0,29,0,0,0,192,1,0,0,57],[0,0,0,64,0,16,4,63,0,0,0,9,1,0,0,57,0,1,0,0,0,1,0,29,0,0,0,0,3,1,4,26],[0,0,1,64,5,48,1,151,0,0,0,128,0,80,4,63,0,0,0,128,1,48,2,112,0,0,0,160,0,16,4,63],[0,0,1,64,3,48,0,156,0,5,0,0,0,6,0,29,0,3,0,0,0,5,0,29,0,0,2,154,0,0,33,61],[0,0,0,0,3,5,0,75,0,0,2,159,0,0,193,61,0,0,0,0,1,2,0,75,0,0,2,253,0,0,193,61],[0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63],[0,0,0,33,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,112,1,0,0,65,0,0,1,4,0,16,4,63],[0,0,1,113,1,0,0,65,0,0,2,94,0,0,1,61,0,0,0,0,3,97,0,75,0,0,2,161,0,0,97,61],[0,0,1,64,2,16,0,156,0,0,0,173,0,0,97,61,0,0,2,188,0,0,1,61,0,0,0,5,3,16,0,108],[0,0,2,188,0,0,193,61,0,0,0,0,1,2,0,75,0,0,2,243,0,0,193,61,0,0,0,3,2,0,0,41],[0,0,0,2,1,32,0,108,0,0,3,39,0,0,193,61,0,0,0,5,1,0,0,41,0,0,0,1,1,16,0,138],[0,0,1,64,2,16,0,156,0,0,0,173,0,0,33,61,0,0,1,64,1,16,1,151,0,0,1,1,33,16,1,26],[0,0,0,11,1,32,0,57,0,0,0,0,1,1,4,26,0,0,0,4,1,16,0,107,0,0,3,152,0,0,193,61],[0,0,0,6,1,0,0,107,0,0,3,100,0,0,97,61,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,60,1,0,0,57,0,0,0,228,0,16,4,63],[0,0,1,102,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,103,1,0,0,65,0,0,2,94,0,0,1,61],[0,0,0,1,2,16,0,57,0,0,0,5,2,32,0,108,0,0,3,9,0,0,193,61,0,0,0,1,2,16,0,138],[0,0,1,64,3,32,0,156,0,0,0,173,0,0,33,61,0,0,0,10,3,0,0,57,0,0,0,0,3,3,4,26],[0,0,1,64,2,32,1,151,0,0,1,1,82,32,1,26,0,0,0,11,2,80,0,57,0,0,0,0,2,2,4,26],[0,0,0,224,0,16,4,63,0,0,0,3,1,0,0,41,0,0,1,0,0,16,4,63,0,0,1,32,0,32,4,63],[0,0,1,64,0,48,4,63,0,0,0,192,0,64,4,63,0,0,1,96,1,0,0,57,0,0,0,64,0,16,4,63],[0,0,1,24,1,0,0,65,0,0,0,0,2,0,4,20,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,1,86,1,16,1,199,0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,4,3,0,0,41,0,0,3,150,0,0,97,61,0,0,0,64,2,0,4,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,19,0,75,0,0,3,162,0,0,193,61,0,0,0,3,3,0,0,41],[0,0,0,2,1,48,0,107,0,0,3,197,0,0,161,61,0,0,1,94,1,32,0,156,0,0,1,83,0,0,33,61],[0,0,0,64,1,32,0,57,0,0,0,64,0,16,4,63,0,0,0,32,1,32,0,57,0,0,0,5,4,0,0,41],[0,0,0,0,0,65,4,53,0,0,0,2,3,0,0,41,0,0,0,0,0,50,4,53,0,0,0,128,1,64,2,16],[0,0,0,0,1,19,1,159,0,0,0,1,2,0,0,41,0,0,0,0,0,18,4,27,0,0,0,1,1,64,0,138],[0,0,1,64,2,16,0,156,0,0,0,173,0,0,33,61,0,0,3,93,0,0,1,61,0,0,1,71,1,0,0,65],[0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,53,1,0,0,57],[0,0,0,228,0,16,4,63,0,0,1,95,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,96,1,0,0,65],[0,0,2,94,0,0,1,61,0,0,0,5,1,0,0,107,0,0,3,49,0,0,193,61,0,0,1,71,1,0,0,65],[0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,44,1,0,0,57],[0,0,0,228,0,16,4,63,0,0,1,110,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,111,1,0,0,65],[0,0,2,94,0,0,1,61,0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,196,0,16,4,63,0,0,0,27,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,84,1,0,0,65],[0,0,2,82,0,0,1,61,0,0,0,64,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,32,2,16,0,57],[0,0,0,4,3,0,0,41,0,0,0,0,0,50,4,53,0,0,0,5,2,0,0,41,0,0,0,0,0,33,4,53],[0,0,0,128,1,48,2,16,0,0,1,64,2,32,1,151,0,0,0,0,1,18,1,159,0,0,0,3,2,0,0,41],[0,0,0,0,0,18,4,27,0,0,0,100,1,0,0,57,0,0,0,0,1,16,3,103,0,0,0,0,1,1,4,59],[0,0,0,6,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,4,1,0,0,57,0,0,0,6,2,0,0,41],[0,0,0,0,0,33,4,28,0,0,0,0,1,0,0,25,0,0,4,90,0,1,4,46,0,0,1,71,1,0,0,65],[0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63,0,0,0,47,1,0,0,57],[0,0,0,228,0,16,4,63,0,0,1,98,1,0,0,65,0,0,1,4,0,16,4,63,0,0,1,99,1,0,0,65],[0,0,2,94,0,0,1,61,0,0,0,5,1,0,0,41,0,0,1,64,1,16,0,65,0,3,0,0,0,1,0,29],[0,0,0,224,1,16,2,16,0,0,0,224,0,16,4,63,0,0,0,4,1,0,0,57,0,0,0,192,0,16,4,63],[0,0,1,0,1,0,0,57,0,0,0,64,0,16,4,63,0,0,1,24,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,1,104,1,16,1,199],[0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,4,3,0,0,41],[0,0,3,150,0,0,97,61,0,0,0,64,2,0,4,61,0,0,0,0,1,1,4,59,0,0,0,0,1,49,0,75],[0,0,3,171,0,0,193,61,0,0,0,3,1,0,0,41,0,0,1,64,1,16,1,151,0,0,1,1,49,16,1,26],[0,0,0,11,1,48,0,57,0,0,0,4,3,0,0,41,0,0,0,0,0,49,4,27,0,0,1,94,1,32,0,156],[0,0,1,83,0,0,33,61,0,0,0,64,1,32,0,57,0,0,0,64,0,16,4,63,0,0,0,32,1,32,0,57],[0,0,0,5,4,0,0,41,0,0,0,0,0,65,4,53,0,0,0,2,3,0,0,41,0,0,0,0,0,50,4,53],[0,0,0,128,1,64,2,16,0,0,0,0,1,19,1,159,0,0,0,1,2,0,0,41,0,0,0,0,0,18,4,27],[0,0,0,1,1,64,0,138,0,0,1,64,1,16,1,151,0,0,1,1,33,16,1,26,0,0,0,11,1,32,0,57],[0,0,0,4,2,0,0,41,0,0,0,0,0,33,4,27,0,0,0,10,1,0,0,57,0,0,0,0,0,1,4,27],[0,0,1,13,1,0,0,57,0,0,0,0,2,1,4,26,0,0,1,68,3,32,0,156,0,0,3,191,0,0,129,61],[0,0,0,64,3,0,4,61,0,0,1,94,4,48,0,156,0,0,1,83,0,0,33,61,0,0,0,64,4,48,0,57],[0,0,0,64,0,64,4,63,0,0,1,12,4,0,0,57,0,0,0,0,6,4,4,26,0,0,1,64,4,96,1,151],[0,0,0,0,4,67,4,54,0,0,0,128,5,96,2,112,0,0,0,0,0,84,4,53,0,0,1,64,6,96,0,156],[0,0,3,220,0,0,33,61,0,0,0,0,6,3,4,51,0,0,1,64,6,96,1,152,0,0,3,220,0,0,193,61],[0,0,0,7,5,0,0,57,0,0,0,0,5,5,4,26,0,0,0,128,5,80,2,112,0,0,0,0,0,84,4,53],[0,0,1,107,2,32,1,151,0,0,0,0,2,37,1,159,0,0,0,0,0,33,4,27,0,0,0,6,6,0,0,107],[0,0,3,223,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,1,108,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,1,109,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,40,3,0,0,57,0,0,0,0,0,50,4,53,0,0,1,71,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,1,24,2,0,0,65,0,0,1,24,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,1,89,1,16,1,199,0,0,4,91,0,1,4,48,0,0,0,0,1,0,0,25,0,0,4,91,0,1,4,48],[0,0,1,71,1,0,0,65,0,0,0,192,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,196,0,16,4,63],[0,0,0,51,1,0,0,57,0,0,0,228,0,16,4,63,0,0,1,100,1,0,0,65,0,0,1,4,0,16,4,63],[0,0,1,101,1,0,0,65,0,0,2,94,0,0,1,61,0,0,0,100,1,32,0,57,0,0,1,87,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,68,1,32,0,57,0,0,1,88,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,36,1,32,0,57,0,0,0,38,3,0,0,57,0,0,3,179,0,0,1,61,0,0,0,100,1,32,0,57],[0,0,1,105,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,68,1,32,0,57,0,0,1,106,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,36,1,32,0,57,0,0,0,39,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,1,71,1,0,0,65,0,0,0,0,0,18,4,53,0,0,0,4,1,32,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,1,24,1,0,0,65,0,0,1,24,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,1,89,1,16,1,199,0,0,4,91,0,1,4,48,0,0,0,1,1,0,0,41],[0,0,0,0,1,1,4,26,0,0,1,12,2,0,0,57,0,0,0,0,0,18,4,27,0,0,0,0,1,0,0,25],[0,0,4,90,0,1,4,46,0,0,0,132,1,32,0,57,0,0,1,90,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,100,1,32,0,57,0,0,1,91,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,68,1,32,0,57],[0,0,1,92,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,36,1,32,0,57,0,0,0,93,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,1,71,1,0,0,65,0,0,0,0,0,18,4,53,0,0,0,4,1,32,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,49,4,53,0,0,1,24,1,0,0,65,0,0,1,24,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,1,93,1,16,1,199,0,0,4,91,0,1,4,48],[0,0,0,6,6,0,0,107,0,0,3,225,0,0,193,61,0,0,3,195,0,0,1,61,0,0,0,6,6,0,0,41],[0,6,0,1,0,96,0,146,0,0,0,6,5,80,0,41,0,0,1,64,6,80,0,156,0,0,0,173,0,0,33,61],[0,0,0,0,0,84,4,53,0,0,0,2,5,0,0,41,0,0,0,0,0,83,4,53,0,0,0,0,5,4,4,51],[0,0,1,64,6,80,1,151,0,0,0,5,6,96,0,108,0,0,3,237,0,0,129,61,0,0,0,128,5,80,2,16],[0,0,3,244,0,0,1,61,0,0,0,5,6,0,0,41,0,0,0,128,5,96,2,16,0,0,0,0,2,82,1,159],[0,0,0,0,0,33,4,27,0,0,0,0,0,100,4,53,0,0,0,0,1,3,4,51,0,2,0,0,0,1,0,29],[0,0,0,2,1,0,0,41,0,0,1,64,1,16,1,151,0,0,0,0,1,81,1,159,0,0,3,193,0,0,1,61],[0,0,0,0,1,1,0,75,0,0,3,251,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,1,114,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53,0,0,1,71,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,1,24,2,0,0,65],[0,0,1,24,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,1,125,1,16,1,199],[0,0,4,91,0,1,4,48,0,0,1,126,2,16,0,156,0,0,4,18,0,0,129,61,0,0,0,64,1,16,0,57],[0,0,0,64,0,16,4,63,0,0,0,0,0,1,4,45,0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48],[0,0,0,64,3,0,4,61,0,0,1,126,1,48,0,156,0,0,4,37,0,0,129,61,0,0,0,64,1,48,0,57],[0,0,0,64,0,16,4,63,0,0,0,7,1,0,0,57,0,0,0,0,2,1,4,26,0,0,0,32,4,48,0,57],[0,0,0,128,1,32,2,112,0,0,0,0,0,20,4,53,0,0,1,64,2,32,1,151,0,0,0,0,0,35,4,53],[0,0,0,0,0,1,4,45,0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48,0,0,0,64,3,0,4,61],[0,0,1,126,1,48,0,156,0,0,4,56,0,0,129,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63],[0,0,0,9,1,0,0,57,0,0,0,0,2,1,4,26,0,0,0,32,4,48,0,57,0,0,0,128,1,32,2,112],[0,0,0,0,0,20,4,53,0,0,1,64,2,32,1,151,0,0,0,0,0,35,4,53,0,0,0,0,0,1,4,45],[0,0,1,123,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63],[0,0,1,124,1,0,0,65,0,0,4,91,0,1,4,48,0,0,1,24,3,0,0,65,0,0,1,24,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,64,1,16,2,16,0,0,1,24,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20,0,0,1,24,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,1,127,1,16,1,199],[0,0,128,16,2,0,0,57,4,89,4,84,0,0,4,15,0,0,0,1,2,32,1,144,0,0,4,82,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,4,91,0,1,4,48],[0,0,4,87,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,4,89,0,0,4,50,0,0,4,90,0,1,4,46,0,0,4,91,0,1,4,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,225,188,155,240,64,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,223,81,252],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,166,174,10,171],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,208,242,198,98],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,221,234,168,229],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,221,234,168,230],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,23,59,151],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,208,242,198,99],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,212,164,202,13],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,166,174,10,172],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,168,81,174,120],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,191,31,228,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,139,95,49],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,139,95,50],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154,138,5,146],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,160,128,62,247],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,223,81,253],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,138,200,76,14],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,142,138,207,135],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,54,53,243,229],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,119,167,150],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,155,209,242],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,124,155,209,243],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,180,18,70],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,120,119,167,151],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,121,107,137,185],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,54,53,243,230],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,203,177,92],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,242,92,58],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,202,228,97],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,202,228,98],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,241,114,173],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,229,204,189],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,250,87,121],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,190,208,54],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,231,81,123],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,224,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,99,117,114,114,101,110,116,32,98,97,116,99,104,32,110,117,109,98,101,114,32,109,117,115,116,32,98,101],[32,103,114,101,97,116,101,114,32,116,104,97,110,32,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,1,0,0,0,0,0,0,0,0,0],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0],[84,104,101,114,101,32,109,117,115,116,32,98,101,32,97,32,118,105,114,116,117,97,108,32,98,108,111,99,107,32,99,114],[101,97,116,101,100,32,97,116,32,116,104,101,32,115,116,97,114,116,32,111,102,32,116,104,101,32,98,97,116,99,104,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,76,50,32,98,108,111,99,107,32,109,117],[115,116,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,111,114,32,101,113,117,97,108,32,116,111,32,116],[104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,99,117,114,114,101,110,116,32,98,97,116,99],[104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,196,0,0,0,128,0,0,0,0,0,0,0,0],[73,110,118,97,108,105,100,32,110,101,119,32,76,50,32,98,108,111,99,107,32,110,117,109,98,101,114,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,192,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,0,0,0,224,0,0,0,0,0,0,0,0],[111,114,114,101,99,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,99,117,114,114,101,110,116,32,76,50,32,98,108,111,99,107,32,104,97,115,104,32,105,115,32,105,110,99],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[116,97,109,112,32,111,102,32,116,104,101,32,112,114,101,118,105,111,117,115,32,76,50,32,98,108,111,99,107,0,0,0],[107,32,109,117,115,116,32,98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,116,105,109,101,115],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,110,101,119,32,76,50,32,98,108,111,99],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,191],[67,97,110,32,110,111,116,32,114,101,117,115,101,32,76,50,32,98,108,111,99,107,32,110,117,109,98,101,114,32,102,114],[111,109,32,116,104,101,32,112,114,101,118,105,111,117,115,32,98,97,116,99,104,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,192,0,0,0,0,0,0,0,0],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,115,97,109,101,32,76,50,32,98,108,111],[99,107,32,109,117,115,116,32,98,101,32,115,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,112,114,101,118,105,111,117,115,32,104,97,115,104,32,111,102,32,116,104,101,32,115,97,109,101,32,76,50],[32,98,108,111,99,107,32,109,117,115,116,32,98,101,32,115,97,109,101,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,110,32,110,111,116,32,99,114,101,97,116,101,32,118,105,114,116,117,97,108,32,98,108,111,99,107,115,32,105,110],[32,116,104,101,32,109,105,100,100,108,101,32,111,102,32,116,104,101,32,109,105,110,105,98,108,111,99,107,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,224,0,0,0,0,0,0,0,0],[99,111,114,114,101,99,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,112,114,101,118,105,111,117,115,32,76,50,32,98,108,111,99,107,32,104,97,115,104,32,105,115,32,105,110],[255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,108,32,98,108,111,99,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,110,39,116,32,105,110,105,116,105,97,108,105,122,101,32,116,104,101,32,102,105,114,115,116,32,118,105,114,116,117],[76,50,32,98,108,111,99,107,32,110,117,109,98,101,114,32,105,115,32,110,101,118,101,114,32,101,120,112,101,99,116,101],[100,32,116,111,32,98,101,32,122,101,114,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[85,112,103,114,97,100,101,32,116,114,97,110,115,97,99,116,105,111,110,32,109,117,115,116,32,98,101,32,102,105,114,115],[116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[84,105,109,101,115,116,97,109,112,115,32,115,104,111,117,108,100,32,98,101,32,105,110,99,114,101,109,101,110,116,97,108],[84,104,101,32,112,114,111,118,105,100,101,100,32,98,108,111,99,107,32,110,117,109,98,101,114,32,105,115,32,110,111,116],[32,99,111,114,114,101,99,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102,32,116,104,101,32,98,97,116,99,104,32,109,117,115,116,32],[98,101,32,103,114,101,97,116,101,114,32,116,104,97,110,32,116,104,101,32,116,105,109,101,115,116,97,109,112,32,111,102],[32,116,104,101,32,112,114,101,118,105,111,117,115,32,98,108,111,99,107,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,192,0,0,0,0,0,0,0,0],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,192],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[24,39,86,27,18,102,204,92,30,2,117,140,74,185,186,92,56,38,42,164,136,173,174,88,124,113,102,32,107,183,146,68]],"0x000000000000000000000000000000000000800c":[[0,2,0,0,0,0,0,2,0,17,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,5,48,2,112,0,0,7,155,0,80,1,157,0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63],[0,0,7,155,3,80,1,151,0,0,0,1,2,32,1,144,0,0,0,111,0,0,193,61,0,0,0,4,2,48,0,140],[0,0,0,159,0,0,65,61,0,0,0,0,2,1,4,59,0,0,7,157,2,32,1,151,0,0,7,158,2,32,0,156],[0,0,0,159,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,159,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,6,32,0,140,0,0,0,159,0,0,65,61,0,0,0,4,6,16,3,112],[0,0,0,0,13,6,4,59,0,0,7,159,6,208,0,156,0,0,0,159,0,0,33,61,0,0,0,0,2,210,0,73],[0,0,7,160,6,0,0,65,0,0,2,96,7,32,0,140,0,0,0,0,7,0,0,25,0,0,0,0,7,6,64,25],[0,0,7,160,2,32,1,151,0,0,0,0,8,2,0,75,0,0,0,0,6,0,160,25,0,0,7,160,2,32,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,2,6,0,75,0,0,0,159,0,0,193,61,0,0,0,4,12,208,0,57],[0,0,0,0,2,193,3,79,0,0,0,0,2,2,4,59,0,0,0,0,6,2,0,75,0,0,0,119,0,0,193,61],[0,0,0,0,2,49,3,79,0,0,1,0,5,192,0,57,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59],[0,0,0,128,6,64,0,140,0,0,0,161,0,0,65,61,0,0,0,128,6,64,2,112,0,0,7,168,7,64,0,156],[0,0,0,0,6,4,160,25,0,0,7,168,7,64,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57],[0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112],[0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112],[0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,32,7,0,0,138],[0,0,0,193,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57],[0,0,0,128,0,112,4,63,0,0,0,33,7,96,0,57,0,0,0,5,7,112,2,114,0,0,0,93,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,5,9,128,2,16,0,0,0,0,10,146,3,79,0,0,0,0,10,10,4,59],[0,0,0,160,9,144,0,57,0,0,0,0,0,169,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,120,0,75],[0,0,0,85,0,0,65,61,0,0,0,0,7,0,0,75,0,0,0,95,0,0,97,61,0,0,0,128,7,0,4,61],[0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,160,7,0,4,61,0,0,7,167,7,112,1,151],[0,0,0,248,8,96,2,16,0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,160,0,112,4,63],[0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,4,100,1,207,0,0,0,255,6,96,0,140],[0,0,0,0,4,0,32,25,0,0,0,161,0,64,4,63,0,0,0,174,0,0,1,61,0,0,0,0,1,0,4,22],[0,0,0,0,1,1,0,75,0,0,0,159,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67],[0,0,1,32,0,0,4,67,0,0,7,156,1,0,0,65,0,0,30,105,0,1,4,46,0,0,0,113,6,32,0,140],[0,0,0,251,0,0,193,61,0,0,1,196,2,208,0,57,0,0,0,0,2,33,3,79,0,0,0,0,6,211,0,73],[0,0,0,35,6,96,0,138,0,0,0,0,2,2,4,59,0,0,7,160,7,0,0,65,0,0,0,0,8,98,0,75],[0,0,0,0,8,0,0,25,0,0,0,0,8,7,128,25,0,0,7,160,6,96,1,151,0,0,7,160,9,32,1,151],[0,0,0,0,10,105,0,75,0,0,0,0,7,0,128,25,0,0,0,0,6,105,1,63,0,0,7,160,6,96,0,156],[0,0,0,0,7,8,192,25,0,0,0,0,6,7,0,75,0,0,0,159,0,0,193,61,0,0,0,0,2,194,0,25],[0,0,0,0,6,33,3,79,0,0,0,0,6,6,4,59,0,0,7,159,7,96,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,7,99,0,73,0,0,0,32,2,32,0,57,0,0,7,160,8,0,0,65,0,0,0,0,9,114,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,8,32,25,0,0,7,160,7,112,1,151,0,0,7,160,10,32,1,151],[0,0,0,0,11,122,0,75,0,0,0,0,8,0,128,25,0,0,0,0,7,122,1,63,0,0,7,160,7,112,0,156],[0,0,0,0,8,9,192,25,0,0,0,0,7,8,0,75,0,0,2,193,0,0,97,61,0,0,0,0,1,0,0,25],[0,0,30,106,0,1,4,48,0,0,0,248,6,64,2,16,0,0,7,160,7,0,0,65,0,0,0,0,4,4,0,75],[0,0,0,0,7,6,192,25,0,0,0,192,4,0,0,57,0,0,0,64,0,64,4,63,0,0,0,1,4,0,0,57],[0,0,0,128,0,64,4,63,0,0,0,0,4,32,3,80,0,0,0,0,4,4,4,59,0,0,7,167,4,64,1,151],[0,0,0,0,4,116,1,159,0,0,0,160,0,64,4,63,0,13,0,0,0,13,0,29,0,12,0,0,0,12,0,29],[0,0,0,64,4,0,4,61,0,0,0,96,5,80,0,138,0,0,0,0,6,81,3,79,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,1,87,0,0,65,61,0,0,0,128,7,96,2,112,0,0,7,168,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,132,0,25,0,0,0,0,9,72,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,132,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,0,233,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,178,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75],[0,0,0,225,0,0,65,61,0,0,0,0,9,0,0,75,0,0,0,235,0,0,97,61,0,0,0,0,9,4,4,51],[0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151],[0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53],[0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,7,64,0,57,0,0,1,215,0,0,1,61,0,0,0,2,1,32,0,140],[0,0,1,93,0,0,193,61,0,13,0,0,0,13,0,29,0,12,0,0,0,12,0,29,0,0,7,164,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65,0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57],[30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61],[0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140,0,0,2,219,0,0,65,61,0,0,0,128,1,64,2,112],[0,0,7,168,2,64,0,156,0,0,0,0,1,4,160,25,0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25],[0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191,0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25],[0,0,0,64,2,16,2,112,0,0,7,159,6,16,0,156,0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191],[0,0,7,155,6,32,0,156,0,0,0,0,1,5,160,25,0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156],[0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191,0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25],[0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57],[0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57,0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25],[0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54,0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,1,69,0,0,97,61,0,0,0,0,8,33,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,1,61,0,0,65,61,0,0,0,0,7,0,0,75,0,0,1,71,0,0,97,61,0,0,0,0,7,3,4,51],[0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57,0,0,2,238,0,0,1,61,0,0,7,166,7,64,0,156],[0,0,1,185,0,0,161,61,0,0,7,195,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,1,196,0,0,1,61,0,0,0,1,1,32,0,140,0,0,1,199,0,0,193,61,0,13,0,0,0,13,0,29],[0,12,0,0,0,12,0,29,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140],[0,0,3,60,0,0,65,61,0,0,0,128,1,64,2,112,0,0,7,168,2,64,0,156,0,0,0,0,1,4,160,25],[0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191],[0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112,0,0,7,159,6,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,7,155,6,32,0,156,0,0,0,0,1,5,160,25],[0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57],[0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54],[0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,1,167,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,1,159,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,1,169,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57],[0,0,3,79,0,0,1,61,0,0,0,64,7,64,0,57,0,0,0,64,0,112,4,63,0,0,0,1,7,0,0,58],[0,0,0,0,7,116,4,54,0,0,0,0,8,32,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,1,209,0,0,193,61,0,0,7,195,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,50,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,7,196,1,0,0,65,0,0,30,106,0,1,4,48,0,0,7,161,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,23,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,7,162,1,0,0,65,0,0,0,196,0,16,4,63,0,0,7,163,1,0,0,65],[0,0,30,106,0,1,4,48,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151,0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53],[0,0,0,64,5,80,0,138,0,0,0,0,6,81,3,79,0,0,0,64,5,0,4,61,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,2,35,0,0,65,61,0,0,0,128,7,96,2,112,0,0,7,168,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,133,0,25,0,0,0,0,9,88,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,133,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,2,17,0,0,97,61],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,184,0,25,0,0,0,0,11,178,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,154,0,75],[0,0,2,9,0,0,65,61,0,0,0,0,9,0,0,75,0,0,2,19,0,0,97,61,0,0,0,0,9,5,4,51],[0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151],[0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53],[0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,7,80,0,57,0,0,2,51,0,0,1,61,0,0,7,166,7,80,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,7,80,0,57,0,0,0,64,0,112,4,63,0,0,0,1,7,0,0,58],[0,0,0,0,7,117,4,54,0,0,0,0,8,32,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151,0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53],[0,0,0,64,11,0,4,61,0,0,0,32,6,176,0,57,0,0,0,0,7,4,4,51,0,0,0,0,8,7,0,75],[0,0,2,65,0,0,97,61,0,0,0,0,8,0,0,25,0,0,0,0,9,104,0,25,0,0,0,32,8,128,0,57],[0,0,0,0,10,72,0,25,0,0,0,0,10,10,4,51,0,0,0,0,0,169,4,53,0,0,0,0,9,120,0,75],[0,0,2,58,0,0,65,61,0,0,0,0,4,103,0,25,0,0,0,0,0,4,4,53,0,0,0,0,6,5,4,51],[0,0,0,0,7,6,0,75,0,0,2,78,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,71,0,25],[0,0,0,32,7,112,0,57,0,0,0,0,9,87,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53],[0,0,0,0,8,103,0,75,0,0,2,71,0,0,65,61,0,0,0,0,4,70,0,25,0,0,0,0,0,4,4,53],[0,0,0,0,4,180,0,73,0,0,0,32,5,64,0,138,0,0,0,0,0,91,4,53,0,0,0,31,4,64,0,57],[0,10,0,32,0,0,0,146,0,0,0,10,4,64,1,127,0,9,0,0,0,11,0,29,0,0,0,0,5,180,0,25],[0,0,0,0,4,69,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,11,0,0,0,5,0,29],[0,0,7,159,5,80,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61],[0,0,0,11,4,0,0,41,0,0,0,64,0,64,4,63,0,0,7,166,4,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,13,7,0,0,41,0,0,0,68,4,112,0,57,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59],[0,0,0,11,8,0,0,41,0,0,0,64,5,128,0,57,0,0,0,64,0,80,4,63,0,0,0,32,5,128,0,57],[0,0,7,170,6,0,0,65,0,0,0,0,0,101,4,53,0,0,0,21,5,0,0,57,0,0,0,0,0,88,4,53],[0,0,0,96,4,64,2,16,0,0,0,33,5,128,0,57,0,0,0,0,0,69,4,53,0,0,1,36,4,112,0,57],[0,0,0,0,5,65,3,79,0,0,0,64,6,0,4,61,0,8,0,0,0,6,0,29,0,0,0,0,5,5,4,59],[0,0,0,128,6,80,0,140,0,0,5,81,0,0,65,61,0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156],[0,0,0,0,6,5,160,25,0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57],[0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112],[0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156],[0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25],[0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112],[0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,65,7,96,0,57],[0,0,0,10,7,112,1,127,0,0,0,8,7,112,0,41,0,0,0,8,8,112,0,108,0,0,0,0,8,0,0,25],[0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57,0,0,0,8,8,0,0,41],[0,0,0,0,7,120,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,2,173,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,167,0,25,0,0,0,0,10,162,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,2,165,0,0,65,61,0,0,0,0,8,0,0,75,0,0,2,175,0,0,97,61,0,0,0,8,8,0,0,41],[0,0,0,0,8,8,4,51,0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61,0,0,0,0,8,7,4,51],[0,0,7,167,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,169,8,128,0,65],[0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207],[0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,8,6,0,0,41,0,0,0,33,6,96,0,57],[0,0,5,99,0,0,1,61,0,0,0,0,7,38,0,26,0,0,0,0,6,0,4,20,0,0,24,103,0,0,65,61],[0,0,0,0,3,115,0,75,0,0,24,103,0,0,65,61,0,13,0,0,0,13,0,29,0,12,0,0,0,12,0,29],[0,0,7,176,3,96,0,156,0,0,3,251,0,0,65,61,0,0,0,68,1,64,0,57,0,0,7,191,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57,0,0,0,8,2,0,0,57,0,0,0,0,0,33,4,53],[0,0,7,161,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57,0,0,0,32,2,0,0,57],[0,0,0,0,0,33,4,53,0,0,7,155,1,0,0,65,0,0,7,155,2,64,0,156,0,0,0,0,4,1,128,25],[0,0,0,64,1,64,2,16,0,0,7,182,1,16,1,199,0,0,30,106,0,1,4,48,0,0,7,166,1,48,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58],[0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103,0,0,0,0,6,33,3,79],[0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25],[0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53,0,0,0,64,4,0,4,61],[0,0,0,13,5,0,0,41,0,0,1,4,6,80,0,57,0,0,0,0,5,97,3,79,0,0,0,0,5,5,4,59],[0,0,0,128,7,80,0,140,0,0,3,157,0,0,65,61,0,0,0,128,7,80,2,112,0,0,7,168,8,80,0,156],[0,0,0,0,7,5,160,25,0,0,7,168,8,80,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,132,0,25,0,0,0,0,9,72,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,132,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,3,42,0,0,97,61],[0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16,0,0,0,0,13,200,0,25],[0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53,0,0,0,1,11,176,0,57],[0,0,0,0,12,155,0,75,0,0,3,34,0,0,65,61,0,0,0,0,9,0,0,75,0,0,3,44,0,0,97,61],[0,0,0,0,9,4,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51],[0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65],[0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,5,117,1,207],[0,0,0,255,7,112,0,140,0,0,0,0,5,0,32,25,0,0,0,33,7,64,0,57,0,0,3,174,0,0,1,61],[0,0,7,166,1,48,0,156,0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63],[0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103],[0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75],[0,0,0,0,8,7,192,25,0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53],[0,0,0,64,4,0,4,61,0,0,0,13,5,0,0,41,0,0,1,4,6,80,0,57,0,0,0,0,5,97,3,79],[0,0,0,0,5,5,4,59,0,0,0,128,7,80,0,140,0,0,4,216,0,0,65,61,0,0,0,128,7,80,2,112],[0,0,7,168,8,80,0,156,0,0,0,0,7,5,160,25,0,0,7,168,8,80,0,156,0,0,0,0,8,0,0,25],[0,0,0,16,8,0,32,57,0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,64,8,112,2,112,0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191],[0,0,7,155,7,128,0,156,0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25],[0,0,0,16,8,144,2,112,0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57],[0,0,0,32,8,0,0,138,0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,132,0,25],[0,0,0,0,9,72,0,75,0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63],[0,0,0,2,8,112,0,57,0,0,0,0,8,132,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114],[0,0,3,139,0,0,97,61,0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16],[0,0,0,0,13,200,0,25,0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53],[0,0,0,1,11,176,0,57,0,0,0,0,12,155,0,75,0,0,3,131,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,3,141,0,0,97,61,0,0,0,0,9,4,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159],[0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137],[0,0,0,0,5,117,1,207,0,0,0,255,7,112,0,140,0,0,0,0,5,0,32,25,0,0,0,33,7,64,0,57],[0,0,4,233,0,0,1,61,0,0,7,166,7,64,0,156,0,0,1,89,0,0,33,61,0,0,0,64,7,64,0,57],[0,0,0,64,0,112,4,63,0,0,0,0,8,33,3,79,0,0,0,1,7,0,0,58,0,0,0,0,7,116,4,54],[0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,9,80,2,16,0,0,7,160,10,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,10,9,192,25],[0,0,7,167,5,128,1,151,0,0,0,0,5,165,1,159,0,0,0,0,0,87,4,53,0,0,0,64,5,0,4,61],[0,0,0,64,7,96,0,138,0,0,0,0,6,113,3,79,0,0,0,0,6,6,4,59,0,0,0,128,8,96,0,140],[0,0,5,170,0,0,65,61,0,0,0,128,8,96,2,112,0,0,7,168,9,96,0,156,0,0,0,0,8,6,160,25],[0,0,7,168,9,96,0,156,0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191],[0,0,7,159,11,128,0,156,0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191,0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,32,10,144,2,112,0,0,7,155,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191],[0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25],[0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57],[0,0,0,0,9,154,1,111,0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,64,57,0,0,7,159,11,144,0,156,0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,149,4,54],[0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114,0,0,3,233,0,0,97,61,0,0,0,0,11,33,3,79],[0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79],[0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75],[0,0,3,225,0,0,65,61,0,0,0,0,10,0,0,75,0,0,3,235,0,0,97,61,0,0,0,0,10,5,4,51],[0,0,0,0,10,10,0,75,0,0,1,193,0,0,97,61,0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151],[0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53],[0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137,0,0,0,0,6,134,1,207,0,0,0,255,8,128,0,140],[0,0,0,0,6,0,32,25,0,0,0,33,8,80,0,57,0,0,5,187,0,0,1,61,0,0,7,155,2,32,1,151],[0,0,0,0,1,33,3,79,0,0,0,0,2,117,0,73,0,0,7,155,2,32,1,151,0,0,0,0,1,33,3,223],[0,0,0,192,2,96,2,16,0,0,7,177,2,32,1,151,0,0,7,178,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,16,2,0,0,57,30,104,30,99,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,7,155,5,48,1,151,0,0,0,1,2,32,1,144,0,0,5,54,0,0,97,61,0,0,0,63,2,80,0,57],[0,0,7,179,2,32,1,151,0,0,0,64,6,0,4,61,0,0,0,0,2,38,0,25,0,0,0,0,3,98,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,4,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,0,4,86,4,54],[0,0,0,1,2,0,3,103,0,0,0,0,3,0,0,49,0,0,0,31,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,4,39,0,0,97,61,0,0,0,0,8,50,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,164,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,4,31,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,4,41,0,0,97,61,0,0,0,31,7,80,1,143,0,0,0,5,5,80,2,114,0,0,4,53,0,0,97,61],[0,0,0,0,8,0,0,25,0,0,0,5,9,128,2,16,0,0,0,0,10,148,0,25,0,0,0,0,9,145,3,79],[0,0,0,0,9,9,4,59,0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,88,0,75],[0,0,4,45,0,0,65,61,0,0,0,0,8,7,0,75,0,0,4,68,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25,0,0,0,3,7,112,2,16,0,0,0,0,8,5,4,51],[0,0,0,0,8,120,1,207,0,0,0,0,8,120,2,47,0,0,0,0,1,1,4,59,0,0,1,0,7,112,0,137],[0,0,0,0,1,113,2,47,0,0,0,0,1,113,1,207,0,0,0,0,1,129,1,159,0,0,0,0,0,21,4,53],[0,0,0,0,1,6,4,51,0,0,0,32,1,16,0,140,0,0,12,89,0,0,193,61,0,0,0,13,6,0,0,41],[0,0,0,0,1,99,0,73,0,0,0,35,5,16,0,138,0,11,2,4,0,96,0,61,0,0,0,11,1,32,3,96],[0,0,0,0,1,1,4,59,0,0,7,160,6,0,0,65,0,0,0,0,7,81,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,7,160,5,80,1,151,0,0,7,160,8,16,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,0,12,5,0,0,41,0,0,0,159,0,0,193,61,0,0,0,0,4,4,4,51],[0,10,0,0,0,4,0,29,0,0,0,0,1,81,0,25,0,0,0,0,4,18,3,79,0,0,0,0,5,4,4,59],[0,0,7,159,4,80,0,156,0,0,0,159,0,0,33,61,0,0,0,5,4,80,2,16,0,0,0,0,3,67,0,73],[0,0,0,32,6,16,0,57,0,0,7,160,1,0,0,65,0,0,0,0,7,54,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,1,32,25,0,0,7,160,3,48,1,151,0,0,7,160,8,96,1,151,0,0,0,0,9,56,0,75],[0,0,0,0,1,0,128,25,0,0,0,0,3,56,1,63,0,0,7,160,3,48,0,156,0,0,0,0,1,7,192,25],[0,0,0,0,1,1,0,75,0,0,0,159,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,32,3,16,0,57],[0,0,7,180,5,80,1,152,0,0,4,128,0,0,97,61,0,0,0,0,2,98,3,79,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,115,0,25,0,0,0,0,7,114,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,4,120,0,0,65,61],[0,0,0,0,2,0,0,75,0,0,4,130,0,0,97,61,0,0,0,0,0,65,4,53,0,0,0,63,2,64,0,57],[0,0,0,32,4,0,0,138,0,0,0,0,2,66,1,111,0,0,0,0,2,33,0,25,0,0,0,0,4,18,0,75],[0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57,0,0,7,159,5,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,32,4,63,0,0,7,155,2,0,0,65],[0,0,7,155,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,64,3,48,2,16,0,0,0,0,1,1,4,51],[0,0,7,155,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159],[0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,12,10,0,0,41,0,0,0,13,3,0,0,41,0,0,0,159,0,0,97,61],[0,0,0,0,2,0,0,49,0,0,0,0,3,50,0,73,0,0,0,35,5,48,0,138,0,0,0,11,3,0,0,41],[0,0,0,32,4,48,0,57,0,0,0,1,3,0,3,103,0,0,0,0,4,67,3,79,0,0,0,0,4,4,4,59],[0,0,7,160,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25],[0,0,7,160,5,80,1,151,0,0,7,160,8,64,1,151,0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25],[0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25,0,0,0,0,1,1,4,59],[0,11,0,0,0,1,0,29,0,0,0,0,1,6,0,75,0,0,0,159,0,0,193,61,0,0,0,0,1,164,0,25],[0,0,0,0,4,19,3,79,0,0,0,0,4,4,4,59,0,0,7,159,5,64,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,5,66,0,73,0,0,0,32,1,16,0,57,0,0,7,160,6,0,0,65,0,0,0,0,7,81,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,6,32,25,0,0,7,160,5,80,1,151,0,0,7,160,8,16,1,151],[0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,0,159,0,0,193,61,0,0,0,0,5,20,0,26],[0,0,0,0,4,0,4,20,0,0,24,103,0,0,65,61,0,0,0,0,6,82,0,75,0,0,24,103,0,0,65,61],[0,0,7,176,6,64,0,156,0,0,11,97,0,0,65,61,0,0,0,64,4,0,4,61,0,0,2,202,0,0,1,61],[0,0,7,166,7,64,0,156,0,0,1,89,0,0,33,61,0,0,0,64,7,64,0,57,0,0,0,64,0,112,4,63],[0,0,0,0,8,33,3,79,0,0,0,1,7,0,0,58,0,0,0,0,7,116,4,54,0,0,0,0,8,128,3,80],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61,0,0,0,248,9,80,2,16],[0,0,7,160,10,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,10,9,192,25,0,0,7,167,5,128,1,151],[0,0,0,0,5,165,1,159,0,0,0,0,0,87,4,53,0,0,0,64,5,0,4,61,0,0,0,96,6,96,0,138],[0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,128,8,112,0,140,0,0,6,8,0,0,65,61],[0,0,0,128,8,112,2,112,0,0,7,168,9,112,0,156,0,0,0,0,8,7,160,25,0,0,7,168,9,112,0,156],[0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191,0,0,7,159,11,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,4,11,160,1,191,0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112],[0,0,7,155,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140],[0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140],[0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111],[0,0,0,0,9,149,0,25,0,0,0,0,10,89,0,75,0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57],[0,0,7,159,11,144,0,156,0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,149,4,54,0,0,0,33,10,128,0,57],[0,0,0,5,10,160,2,114,0,0,5,36,0,0,97,61,0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25],[0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59],[0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75,0,0,5,28,0,0,65,61],[0,0,0,0,10,0,0,75,0,0,5,38,0,0,97,61,0,0,0,0,10,5,4,51,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16],[0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16],[0,0,0,248,8,128,0,137,0,0,0,0,7,135,1,207,0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25],[0,0,0,33,8,80,0,57,0,0,6,25,0,0,1,61,0,0,0,31,3,80,1,143,0,0,0,5,2,80,2,114],[0,0,5,65,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,5,6,64,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,4,64,0,57,0,0,0,0,6,36,0,75],[0,0,5,58,0,0,65,61,0,0,0,0,4,3,0,75,0,0,5,79,0,0,97,61,0,0,0,3,3,48,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,4,2,4,51,0,0,0,0,4,52,1,207,0,0,0,0,4,52,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,65,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,80,2,16],[0,0,30,106,0,1,4,48,0,0,0,8,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,8,7,0,0,41,0,0,0,64,6,112,0,57,0,0,0,64,0,96,4,63,0,0,0,1,6,0,0,58],[0,0,0,0,6,103,4,54,0,0,0,0,7,32,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75],[0,0,0,0,9,8,192,25,0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53],[0,0,0,12,11,0,0,41,0,0,0,0,5,179,0,73,0,0,0,160,6,64,0,57,0,0,0,0,4,97,3,79],[0,0,0,0,4,4,4,59,0,0,0,31,5,80,0,138,0,0,7,160,7,80,1,151,0,0,7,160,8,64,1,151],[0,0,7,160,9,0,0,65,0,0,0,0,10,120,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,64,25],[0,0,0,0,7,120,1,63,0,0,0,0,8,84,0,75,0,0,0,0,9,0,64,25,0,0,7,160,7,112,0,156],[0,0,0,0,10,9,192,25,0,0,0,0,7,10,0,75,0,0,0,159,0,0,193,61,0,0,0,0,8,180,0,25],[0,0,0,0,7,129,3,79,0,0,0,0,7,7,4,59,0,0,7,159,9,112,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,9,115,0,73,0,0,0,32,8,128,0,57,0,0,7,160,10,0,0,65,0,0,0,0,11,152,0,75],[0,0,0,0,11,0,0,25,0,0,0,0,11,10,32,25,0,0,7,160,9,144,1,151,0,0,7,160,12,128,1,151],[0,0,0,0,13,156,0,75,0,0,0,0,10,0,128,25,0,0,0,0,9,156,1,63,0,0,7,160,9,144,0,156],[0,0,0,0,10,11,192,25,0,0,0,0,9,10,0,75,0,0,0,159,0,0,193,61,0,0,0,1,9,112,0,140],[0,0,7,171,0,0,193,61,0,0,0,0,2,129,3,79,0,0,0,0,2,2,4,59,0,0,0,1,7,0,0,138],[0,0,7,160,8,0,0,65,0,0,0,0,7,114,0,75,0,0,0,0,7,0,0,25,0,0,0,0,7,8,32,25],[0,0,7,160,2,32,1,151,0,0,7,160,9,32,0,156,0,0,0,0,8,0,128,25,0,0,7,160,2,32,1,103],[0,0,7,160,2,32,0,156,0,0,0,0,8,7,192,25,0,7,0,96,0,0,0,61,0,0,0,0,2,8,0,75],[0,0,7,231,0,0,193,61,0,0,0,64,2,0,4,61,0,7,0,0,0,2,0,29,0,0,7,166,2,32,0,156],[0,0,1,89,0,0,33,61,0,0,0,7,8,0,0,41,0,0,0,64,2,128,0,57,0,0,0,64,0,32,4,63],[0,0,0,32,2,128,0,57,0,0,7,169,7,0,0,65,0,0,0,0,0,114,4,53,0,0,0,1,2,0,0,57],[0,0,0,0,0,40,4,53,0,0,7,231,0,0,1,61,0,0,7,166,8,80,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,10,96,2,16,0,0,7,160,11,0,0,65,0,0,0,0,6,6,0,75],[0,0,0,0,11,10,192,25,0,0,7,167,6,144,1,151,0,0,0,0,6,182,1,159,0,0,0,0,0,104,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,7,112,0,138,0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59],[0,0,0,128,9,128,0,140,0,0,6,102,0,0,65,61,0,0,0,128,9,128,2,112,0,0,7,168,10,128,0,156],[0,0,0,0,9,8,160,25,0,0,7,168,10,128,0,156,0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57],[0,0,0,8,11,160,1,191,0,0,7,159,12,144,0,156,0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112],[0,0,7,159,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191,0,0,7,155,9,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,7,155,9,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112],[0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138],[0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,166,0,25,0,0,0,0,11,106,0,75],[0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,11,176,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57],[0,0,0,0,10,166,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114,0,0,5,246,0,0,97,61],[0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25],[0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57],[0,0,0,0,14,189,0,75,0,0,5,238,0,0,65,61,0,0,0,0,11,0,0,75,0,0,5,248,0,0,97,61],[0,0,0,0,11,6,4,51,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,0,0,11,10,4,51],[0,0,7,167,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159,0,0,7,169,11,176,0,65],[0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207],[0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,96,0,57,0,0,6,119,0,0,1,61],[0,0,7,166,8,80,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,80,0,57,0,0,0,64,0,128,4,63],[0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,133,4,54,0,0,0,0,9,144,3,80],[0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,1,193,0,0,97,61,0,0,0,248,10,112,2,16],[0,0,7,160,11,0,0,65,0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25,0,0,7,167,7,144,1,151],[0,0,0,0,7,183,1,159,0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61,0,0,0,64,6,96,0,138],[0,0,0,0,8,97,3,79,0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140,0,0,6,197,0,0,65,61],[0,0,0,128,9,128,2,112,0,0,7,168,10,128,0,156,0,0,0,0,9,8,160,25,0,0,7,168,10,128,0,156],[0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191,0,0,7,159,12,144,0,156],[0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112,0,0,7,159,12,144,0,156,0,0,0,0,10,9,160,25],[0,0,0,4,12,176,1,191,0,0,7,155,9,160,0,156,0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112],[0,0,7,155,9,160,0,156,0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140],[0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140],[0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111],[0,0,0,0,10,167,0,25,0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57],[0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61,0,0,0,1,11,176,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54,0,0,0,33,11,144,0,57],[0,0,0,5,11,176,2,114,0,0,6,84,0,0,97,61,0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25],[0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59],[0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75,0,0,6,76,0,0,65,61],[0,0,0,0,11,0,0,75,0,0,6,86,0,0,97,61,0,0,0,0,11,7,4,51,0,0,0,0,11,11,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,11,10,4,51,0,0,7,167,11,176,1,151,0,0,0,248,12,144,2,16],[0,0,0,0,11,188,1,159,0,0,7,169,11,176,0,65,0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16],[0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25],[0,0,0,33,9,112,0,57,0,0,6,214,0,0,1,61,0,0,7,166,9,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58],[0,0,0,0,9,150,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,12,11,192,25,0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53],[0,0,0,64,8,0,4,61,0,11,0,64,0,112,0,146,0,0,0,11,9,16,3,96,0,0,0,0,9,9,4,59],[0,0,0,128,10,144,0,140,0,0,7,54,0,0,65,61,0,0,0,128,10,144,2,112,0,0,7,168,11,144,0,156],[0,0,0,0,10,9,160,25,0,0,7,168,11,144,0,156,0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57],[0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156,0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112],[0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191,0,0,7,155,10,176,0,156],[0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25],[0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112],[0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138],[0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75],[0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57,0,0,7,159,13,176,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57],[0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114,0,0,6,178,0,0,97,61],[0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16,0,0,0,0,7,251,0,25],[0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59,0,0,0,0,0,247,4,53,0,0,0,1,14,224,0,57],[0,0,0,0,7,206,0,75,0,0,6,170,0,0,65,61,0,0,0,0,7,0,0,75,0,0,6,180,0,0,97,61],[0,0,0,0,7,8,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,0,7,11,4,51],[0,0,7,167,7,112,1,151,0,0,0,248,12,160,2,16,0,0,0,0,7,124,1,159,0,0,7,169,7,112,0,65],[0,0,0,0,0,123,4,53,0,0,0,3,7,160,2,16,0,0,0,248,7,112,0,137,0,0,0,0,9,121,1,207],[0,0,0,255,7,112,0,140,0,0,0,0,9,0,32,25,0,0,0,33,7,128,0,57,0,0,0,0,0,151,4,53],[0,0,7,72,0,0,1,61,0,0,7,166,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,112,0,57],[0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58,0,0,0,0,9,151,4,54],[0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65,0,0,0,0,8,8,0,75,0,0,0,0,12,11,192,25],[0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53,0,0,0,64,9,0,4,61],[0,0,7,166,8,144,0,156,0,0,1,89,0,0,33,61,0,0,0,32,8,96,0,138,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63,0,0,0,32,10,144,0,57],[0,0,7,170,11,0,0,65,0,0,0,0,0,186,4,53,0,0,0,21,10,0,0,57,0,0,0,0,0,169,4,53],[0,0,0,96,8,128,2,16,0,0,0,33,10,144,0,57,0,0,0,0,0,138,4,53,0,0,0,192,6,96,0,57],[0,0,0,0,6,97,3,79,0,0,0,64,8,0,4,61,0,0,0,0,6,6,4,59,0,11,0,0,0,6,0,29],[0,0,0,128,10,96,0,140,0,0,8,159,0,0,65,61,0,0,0,11,6,0,0,41,0,0,0,128,10,96,2,112],[0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156,0,0,0,0,11,0,0,25],[0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156,0,0,0,0,12,11,160,25],[0,0,0,64,11,160,2,112,0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191],[0,0,7,155,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25],[0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57],[0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25],[0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57,0,0,7,159,13,176,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,176,4,63],[0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114],[0,0,7,35,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16],[0,0,0,0,6,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59,0,0,0,0,0,246,4,53],[0,0,0,1,14,224,0,57,0,0,0,0,6,206,0,75,0,0,7,27,0,0,65,61,0,0,0,0,6,0,0,75],[0,0,7,37,0,0,97,61,0,0,0,0,6,8,4,51,0,0,0,0,6,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,6,11,4,51,0,0,7,167,6,96,1,151,0,0,0,248,12,160,2,16,0,0,0,0,6,108,1,159],[0,0,7,169,6,96,0,65,0,0,0,0,0,107,4,53,0,0,0,3,6,160,2,16,0,0,0,248,6,96,0,137],[0,0,0,11,10,96,1,239,0,0,0,255,6,96,0,140,0,0,0,0,10,0,32,25,0,0,0,33,6,128,0,57],[0,0,0,0,0,166,4,53,0,0,8,178,0,0,1,61,0,0,7,166,7,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,7,128,0,57,0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,10,0,0,58],[0,0,0,0,10,168,4,54,0,0,0,0,7,112,3,80,0,0,0,0,11,7,4,59,0,0,0,0,0,186,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,7,144,2,16,0,0,7,160,12,0,0,65,0,0,0,0,9,9,0,75],[0,0,0,0,12,7,192,25,0,0,7,167,7,176,1,151,0,0,0,0,7,199,1,159,0,0,0,0,0,122,4,53],[0,0,0,64,10,0,4,61,0,0,7,166,7,160,0,156,0,0,1,89,0,0,33,61,0,0,0,11,12,0,0,41],[0,0,0,32,7,192,0,138,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,64,9,160,0,57],[0,0,0,64,0,144,4,63,0,0,0,32,9,160,0,57,0,0,7,170,11,0,0,65,0,0,0,0,0,185,4,53],[0,0,0,21,9,0,0,57,0,0,0,0,0,154,4,53,0,0,0,96,7,112,2,16,0,0,0,33,9,160,0,57],[0,0,0,0,0,121,4,53,0,0,0,192,7,192,0,57,0,0,0,0,7,113,3,79,0,0,0,64,9,0,4,61],[0,0,0,0,7,7,4,59,0,11,0,0,0,7,0,29,0,0,0,128,11,112,0,140,0,0,9,86,0,0,65,61],[0,0,0,11,7,0,0,41,0,0,0,128,11,112,2,112,0,0,7,168,12,112,0,156,0,0,0,0,11,7,160,25],[0,0,7,168,12,112,0,156,0,0,0,0,12,0,0,25,0,0,0,16,12,0,32,57,0,0,0,8,13,192,1,191],[0,0,7,159,14,176,0,156,0,0,0,0,13,12,160,25,0,0,0,64,12,176,2,112,0,0,7,159,14,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,4,14,208,1,191,0,0,7,155,11,192,0,156,0,0,0,0,14,13,160,25],[0,0,0,32,13,192,2,112,0,0,7,155,11,192,0,156,0,0,0,0,13,12,160,25,0,0,0,2,7,224,1,191],[0,0,255,255,12,208,0,140,0,0,0,0,7,14,160,25,0,0,0,16,12,208,2,112,0,0,0,0,12,13,160,25],[0,0,0,255,12,192,0,140,0,0,0,1,7,112,32,57,0,0,0,32,12,0,0,138,0,10,0,0,0,7,0,29],[0,0,0,65,13,112,0,57,0,0,0,0,12,205,1,111,0,0,0,0,12,201,0,25,0,0,0,0,13,156,0,75],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,64,57,0,0,7,159,14,192,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,13,208,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63,0,0,0,10,7,0,0,41],[0,0,0,2,12,112,0,57,0,0,0,0,12,201,4,54,0,0,0,33,13,112,0,57,0,0,0,5,13,208,2,114],[0,0,7,151,0,0,97,61,0,0,0,0,14,33,3,79,0,0,0,0,15,0,0,25,0,0,0,5,7,240,2,16],[0,0,0,0,11,124,0,25,0,0,0,0,7,126,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,123,4,53],[0,0,0,1,15,240,0,57,0,0,0,0,7,223,0,75,0,0,7,143,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,7,153,0,0,97,61,0,0,0,0,7,9,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,12,4,51,0,0,7,167,7,112,1,151,0,0,0,10,13,0,0,41,0,0,0,248,11,208,2,16],[0,0,0,0,7,123,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,124,4,53,0,0,0,3,7,208,2,16],[0,0,0,248,7,112,0,137,0,0,0,11,11,112,1,239,0,0,0,255,7,112,0,140,0,0,0,0,11,0,32,25],[0,0,0,33,7,144,0,57,0,0,0,0,0,183,4,53,0,0,9,105,0,0,1,61,0,0,0,64,8,0,4,61],[0,7,0,0,0,8,0,29,0,0,0,56,8,112,0,140,0,0,7,214,0,0,65,61,0,0,0,32,9,112,2,112],[0,0,7,155,8,112,0,156,0,0,0,0,9,7,160,25,0,0,7,155,8,112,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,0,7,10,0,0,41,0,0,7,166,10,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,8,152,1,159,0,0,0,7,10,0,0,41,0,0,0,64,9,160,0,57,0,0,0,64,0,144,4,63],[0,0,0,2,9,128,0,58,0,0,0,0,9,154,4,54,0,0,0,0,2,32,3,80,0,0,0,0,2,2,4,59],[0,0,0,0,0,41,4,53,0,0,1,193,0,0,97,61,0,0,7,167,2,32,1,151,0,0,0,248,10,128,2,16],[0,0,0,0,2,42,1,159,0,0,7,171,2,32,1,199,0,0,0,0,0,41,4,53,0,0,0,3,2,128,2,16],[0,0,0,248,2,32,1,95,0,0,0,0,2,39,1,207,0,0,0,7,7,0,0,41,0,0,0,33,7,112,0,57],[0,0,0,0,0,39,4,53,0,0,7,231,0,0,1,61,0,0,0,7,8,0,0,41,0,0,7,166,8,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,7,9,0,0,41,0,0,0,64,8,144,0,57,0,0,0,64,0,128,4,63],[0,0,0,1,8,0,0,58,0,0,0,0,8,137,4,54,0,0,0,0,2,32,3,80,0,0,0,0,2,2,4,59],[0,0,0,0,0,40,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,112,2,16,0,0,7,167,2,32,1,151],[0,0,0,0,2,114,1,159,0,0,7,160,2,32,1,103,0,0,0,0,0,40,4,53,0,0,0,128,2,96,0,138],[0,0,0,0,6,33,3,79,0,0,0,96,2,0,0,57,0,0,0,0,6,6,4,59,0,0,0,0,6,6,0,75],[0,0,8,72,0,0,193,61,0,0,7,160,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,128,25,0,0,7,160,5,80,1,151,0,0,7,160,8,64,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,0,12,5,0,0,41,0,0,0,159,0,0,193,61,0,0,0,9,6,0,0,41],[0,0,0,0,6,6,4,51,0,0,0,128,7,0,4,61,0,0,0,11,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,8,9,0,0,41,0,0,0,0,9,9,4,51,0,0,0,7,10,0,0,41,0,0,0,0,10,10,4,51],[0,0,0,0,5,84,0,25,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59,0,0,7,159,11,64,0,156],[0,0,0,159,0,0,33,61,0,0,0,0,11,67,0,73,0,0,0,32,5,80,0,57,0,0,7,160,12,0,0,65],[0,0,0,0,13,181,0,75,0,0,0,0,13,0,0,25,0,0,0,0,13,12,32,25,0,0,7,160,11,176,1,151],[0,0,7,160,14,80,1,151,0,0,0,0,15,190,0,75,0,0,0,0,12,0,128,25,0,0,0,0,11,190,1,63],[0,0,7,160,11,176,0,156,0,0,0,0,12,13,192,25,0,0,0,0,11,12,0,75,0,0,0,159,0,0,193,61],[0,0,0,0,6,118,0,25,0,0,0,0,6,134,0,25,0,0,0,0,6,150,0,25,0,0,0,0,6,166,0,25],[0,0,0,0,6,70,0,25,0,0,0,0,7,2,4,51,0,0,0,0,6,118,0,25,0,0,0,64,7,0,4,61],[0,0,7,159,6,96,1,151,0,0,0,56,8,96,0,140,0,0,10,83,0,0,65,61,0,0,0,32,9,96,2,112],[0,0,7,155,8,96,0,156,0,0,0,0,9,6,160,25,0,0,7,155,8,96,0,156,0,0,0,0,10,0,0,25],[0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25],[0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25],[0,0,0,1,9,0,32,57,0,0,7,166,10,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,8,152,1,159],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,9,49,3,79,0,0,0,2,3,128,0,58],[0,0,0,0,3,55,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,147,4,53],[0,0,1,193,0,0,97,61,0,0,7,167,9,144,1,151,0,0,0,248,10,128,2,16,0,0,0,0,9,154,1,159],[0,0,7,173,9,144,1,199,0,0,0,0,0,147,4,53,0,0,0,3,3,128,2,16,0,0,0,248,3,48,1,95],[0,0,0,0,3,54,1,207,0,0,0,33,6,112,0,57,0,0,0,0,0,54,4,53,0,0,10,99,0,0,1,61],[0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,7,165,1,16,1,199],[0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,0,0,2,1,4,59,0,0,0,128,1,32,0,140,0,0,10,26,0,0,65,61],[0,0,0,128,1,32,2,112,0,0,7,168,3,32,0,156,0,0,0,0,1,2,160,25,0,0,7,168,3,32,0,156],[0,0,0,0,3,0,0,25,0,0,0,16,3,0,32,57,0,0,0,8,5,48,1,191,0,0,7,159,6,16,0,156],[0,0,0,0,5,3,160,25,0,0,0,64,3,16,2,112,0,0,7,159,6,16,0,156,0,0,0,0,3,1,160,25],[0,0,0,4,1,80,1,191,0,0,7,155,6,48,0,156,0,0,0,0,1,5,160,25,0,0,0,32,6,48,2,112],[0,0,7,155,5,48,0,156,0,0,0,0,6,3,160,25,0,0,0,2,5,16,1,191,0,0,255,255,3,96,0,140],[0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140],[0,0,0,1,5,80,32,57,0,0,0,65,1,80,0,57,0,0,0,10,1,16,1,127,0,0,0,0,1,20,0,25],[0,0,0,0,3,65,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,6,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,0,2,1,80,0,57,0,0,0,0,6,20,4,54,0,0,0,1,1,0,3,103,0,0,0,0,3,0,0,49],[0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,8,141,0,0,97,61,0,0,0,0,8,49,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75],[0,0,8,133,0,0,65,61,0,0,0,0,7,0,0,75,0,0,8,143,0,0,97,61,0,0,0,0,7,4,4,51],[0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151],[0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53],[0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137,0,0,0,0,2,82,1,207,0,0,0,255,5,80,0,140],[0,0,0,0,2,0,32,25,0,0,0,33,5,64,0,57,0,0,10,45,0,0,1,61,0,0,7,166,6,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,6,128,0,57,0,0,0,64,0,96,4,63,0,0,0,0,6,33,3,79],[0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54,0,0,0,0,6,96,3,80,0,0,0,0,11,6,4,59],[0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61,0,0,0,11,13,0,0,41,0,0,0,248,6,208,2,16],[0,0,7,160,12,0,0,65,0,0,0,0,13,13,0,75,0,0,0,0,12,6,192,25,0,0,7,167,6,176,1,151],[0,0,0,0,6,198,1,159,0,0,0,0,0,106,4,53,0,0,0,64,6,0,4,61,0,0,0,32,10,96,0,57],[0,0,0,0,11,3,4,51,0,0,0,0,12,11,0,75,0,0,8,191,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,60,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,8,184,0,0,65,61,0,0,0,0,3,171,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,10,4,4,51,0,0,0,0,11,10,0,75,0,0,8,204,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,75,0,25],[0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75,0,0,8,197,0,0,65,61],[0,0,0,0,3,58,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,5,4,51,0,0,0,0,10,4,0,75],[0,0,8,217,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,0,11,58,0,25,0,0,0,32,10,160,0,57],[0,0,0,0,12,90,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53,0,0,0,0,11,74,0,75],[0,0,8,210,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,7,4,51],[0,0,0,0,5,4,0,75,0,0,8,230,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,10,53,0,25],[0,0,0,32,5,80,0,57,0,0,0,0,11,117,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,69,0,75,0,0,8,223,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,4,9,4,51,0,0,0,0,5,4,0,75,0,0,8,243,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,7,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,10,149,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,167,4,53,0,0,0,0,7,69,0,75,0,0,8,236,0,0,65,61,0,0,0,0,3,52,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,4,8,4,51,0,0,0,0,5,4,0,75,0,0,9,0,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,7,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,9,133,0,25],[0,0,0,0,9,9,4,51,0,0,0,0,0,151,4,53,0,0,0,0,7,69,0,75,0,0,8,249,0,0,65,61],[0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,99,0,73,0,0,0,32,4,48,0,138],[0,0,0,0,0,70,4,53,0,0,0,31,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111],[0,0,0,0,7,100,0,25,0,0,0,0,4,71,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,7,159,5,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,112,4,63,0,0,0,13,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,5,82,0,73,0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,7,160,8,0,0,65],[0,0,0,0,9,84,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,7,160,5,80,1,151],[0,0,7,160,10,64,1,151,0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63],[0,0,7,160,5,80,0,156,0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,0,12,5,0,0,41],[0,0,0,159,0,0,193,61,0,0,0,0,5,84,0,25,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59],[0,0,7,159,8,64,0,156,0,0,0,159,0,0,33,61,0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57],[0,0,7,160,9,0,0,65,0,0,0,0,10,133,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25],[0,0,7,160,8,128,1,151,0,0,7,160,11,80,1,151,0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25],[0,0,0,0,8,139,1,63,0,0,7,160,8,128,0,156,0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75],[0,0,0,159,0,0,193,61,0,0,0,1,8,64,0,140,0,0,12,107,0,0,193,61,0,0,0,0,8,81,3,79],[0,0,0,0,8,8,4,59,0,0,0,1,9,0,0,138,0,0,7,160,10,0,0,65,0,0,0,0,9,152,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,10,32,25,0,0,7,160,8,128,1,151,0,0,7,160,11,128,0,156],[0,0,0,0,10,0,128,25,0,0,7,160,8,128,1,103,0,0,7,160,8,128,0,156,0,0,0,0,10,9,192,25],[0,0,0,96,8,0,0,57,0,0,0,0,9,10,0,75,0,0,12,231,0,0,193,61,0,0,7,166,8,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57],[0,0,7,169,9,0,0,65,0,0,0,0,0,152,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53],[0,0,0,0,8,7,0,25,0,0,12,231,0,0,1,61,0,0,7,166,7,144,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,7,144,0,57,0,0,0,64,0,112,4,63,0,0,0,0,7,33,3,79,0,0,0,1,11,0,0,58],[0,0,0,0,11,185,4,54,0,0,0,0,7,112,3,80,0,0,0,0,12,7,4,59,0,0,0,0,0,203,4,53],[0,0,1,193,0,0,97,61,0,0,0,11,14,0,0,41,0,0,0,248,7,224,2,16,0,0,7,160,13,0,0,65],[0,0,0,0,14,14,0,75,0,0,0,0,13,7,192,25,0,0,7,167,7,192,1,151,0,0,0,0,7,215,1,159],[0,0,0,0,0,123,4,53,0,0,0,64,7,0,4,61,0,0,0,32,11,112,0,57,0,0,0,0,12,3,4,51],[0,0,0,0,13,12,0,75,0,0,9,118,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,189,0,25],[0,0,0,32,13,208,0,57,0,0,0,0,15,61,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53],[0,0,0,0,14,205,0,75,0,0,9,111,0,0,65,61,0,0,0,0,3,188,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,11,4,4,51,0,0,0,0,12,11,0,75,0,0,9,131,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,60,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,76,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,9,124,0,0,65,61,0,0,0,0,3,59,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,4,5,4,51,0,0,0,0,11,4,0,75,0,0,9,144,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,91,0,25],[0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,75,0,75,0,0,9,137,0,0,65,61],[0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,6,4,51,0,0,0,0,5,4,0,75],[0,0,9,157,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,11,53,0,25,0,0,0,32,5,80,0,57],[0,0,0,0,12,101,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53,0,0,0,0,11,69,0,75],[0,0,9,150,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,4,8,4,51],[0,0,0,0,5,4,0,75,0,0,9,170,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,53,0,25],[0,0,0,32,5,80,0,57,0,0,0,0,11,133,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,182,4,53],[0,0,0,0,6,69,0,75,0,0,9,163,0,0,65,61,0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,4,10,4,51,0,0,0,0,5,4,0,75,0,0,9,183,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,6,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,165,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,9,176,0,0,65,61,0,0,0,0,3,52,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,4,9,4,51,0,0,0,0,5,4,0,75,0,0,9,196,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,53,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,149,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,9,189,0,0,65,61],[0,0,0,0,3,52,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,115,0,73,0,0,0,32,4,48,0,138],[0,0,0,0,0,71,4,53,0,0,0,31,4,48,0,57,0,0,0,32,3,0,0,138,0,0,0,0,4,52,1,111],[0,0,0,0,6,116,0,25,0,0,0,0,4,70,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,64,57],[0,0,7,159,5,96,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,96,4,63,0,0,0,13,5,0,0,41,0,0,1,196,4,80,0,57,0,0,0,0,4,65,3,79],[0,0,0,0,5,82,0,73,0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,7,160,8,0,0,65],[0,0,0,0,9,84,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25,0,0,7,160,5,80,1,151],[0,0,7,160,10,64,1,151,0,0,0,0,11,90,0,75,0,0,0,0,8,0,128,25,0,0,0,0,5,90,1,63],[0,0,7,160,5,80,0,156,0,0,0,0,8,9,192,25,0,0,0,0,5,8,0,75,0,0,0,12,5,0,0,41],[0,0,0,159,0,0,193,61,0,0,0,0,5,84,0,25,0,0,0,0,4,81,3,79,0,0,0,0,4,4,4,59],[0,0,7,159,8,64,0,156,0,0,0,159,0,0,33,61,0,0,0,0,8,66,0,73,0,0,0,32,5,80,0,57],[0,0,7,160,9,0,0,65,0,0,0,0,10,133,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25],[0,0,7,160,8,128,1,151,0,0,7,160,11,80,1,151,0,0,0,0,12,139,0,75,0,0,0,0,9,0,128,25],[0,0,0,0,8,139,1,63,0,0,7,160,8,128,0,156,0,0,0,0,9,10,192,25,0,0,0,0,8,9,0,75],[0,0,0,159,0,0,193,61,0,0,0,1,8,64,0,140,0,0,12,174,0,0,193,61,0,0,0,0,8,81,3,79],[0,0,0,0,8,8,4,59,0,0,0,1,9,0,0,138,0,0,7,160,10,0,0,65,0,0,0,0,9,152,0,75],[0,0,0,0,9,0,0,25,0,0,0,0,9,10,32,25,0,0,7,160,8,128,1,151,0,0,7,160,11,128,0,156],[0,0,0,0,10,0,128,25,0,0,7,160,8,128,1,103,0,0,7,160,8,128,0,156,0,0,0,0,10,9,192,25],[0,0,0,96,8,0,0,57,0,0,0,0,9,10,0,75,0,0,13,135,0,0,193,61,0,0,7,166,8,96,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,96,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,96,0,57],[0,0,7,169,9,0,0,65,0,0,0,0,0,152,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,134,4,53],[0,0,0,0,8,6,0,25,0,0,13,135,0,0,1,61,0,0,7,166,1,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,1,64,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,20,4,54],[0,0,0,0,3,0,0,49,0,0,0,1,1,0,3,103,0,0,0,0,6,49,3,79,0,0,0,0,6,96,3,80],[0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,32,2,16],[0,0,7,160,8,0,0,65,0,0,0,0,2,2,0,75,0,0,0,0,8,7,192,25,0,0,7,167,2,96,1,151],[0,0,0,0,2,130,1,159,0,0,0,0,0,37,4,53,0,0,0,64,2,0,4,61,0,0,0,32,5,32,0,57],[0,0,0,0,6,4,4,51,0,0,0,0,7,6,0,75,0,0,10,59,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,0,8,87,0,25,0,0,0,32,7,112,0,57,0,0,0,0,9,71,0,25,0,0,0,0,9,9,4,51],[0,0,0,0,0,152,4,53,0,0,0,0,8,103,0,75,0,0,10,52,0,0,65,61,0,0,0,0,4,86,0,25],[0,0,7,192,5,0,0,65,0,0,0,0,0,84,4,53,0,0,0,0,4,36,0,73,0,0,0,30,5,64,0,138],[0,0,0,0,0,82,4,53,0,0,0,33,4,64,0,57,0,0,0,10,5,64,1,127,0,0,0,0,4,37,0,25],[0,0,0,0,5,84,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,7,159,6,64,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,5,80,1,144,0,0,1,89,0,0,193,61,0,0,0,13,6,0,0,41],[0,0,1,196,5,96,0,57,0,0,0,64,0,64,4,63,0,0,0,0,4,81,3,79,0,0,0,0,5,99,0,73],[0,0,0,35,5,80,0,138,0,0,0,0,4,4,4,59,0,0,7,237,0,0,1,61,0,0,7,166,8,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,0,8,49,3,79],[0,0,0,1,3,0,0,58,0,0,0,0,3,55,4,54,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,131,4,53,0,0,1,193,0,0,97,61,0,0,7,167,8,128,1,151,0,0,0,248,6,96,2,16],[0,0,0,0,6,134,1,159,0,0,7,172,6,96,0,65,0,0,0,0,0,99,4,53,0,0,0,64,3,0,4,61],[0,0,0,32,6,48,0,57,0,0,0,0,8,7,4,51,0,0,0,0,9,8,0,75,0,0,10,112,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,105,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,121,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,10,105,0,0,65,61],[0,0,0,0,7,104,0,25,0,0,0,0,0,7,4,53,0,0,0,128,8,0,4,61,0,0,0,0,9,8,0,75],[0,0,10,125,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,160,11,144,0,57],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,32,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,10,118,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,9,12,0,0,41],[0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75,0,0,10,139,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,10,132,0,0,65,61,0,0,0,0,7,120,0,25],[0,0,0,0,0,7,4,53,0,0,0,11,12,0,0,41,0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75],[0,0,10,153,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57],[0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75],[0,0,10,146,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,8,12,0,0,41],[0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75,0,0,10,167,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,10,160,0,0,65,61,0,0,0,0,7,120,0,25],[0,0,0,0,0,7,4,53,0,0,0,7,12,0,0,41,0,0,0,0,8,12,4,51,0,0,0,0,9,8,0,75],[0,0,10,181,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57],[0,0,0,0,11,201,0,25,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75],[0,0,10,174,0,0,65,61,0,0,0,0,5,81,3,79,0,0,0,0,1,120,0,25,0,0,0,31,7,64,1,143],[0,0,0,0,0,1,4,53,0,0,0,5,8,64,2,114,0,0,10,196,0,0,97,61,0,0,0,0,9,0,0,25],[0,0,0,5,10,144,2,16,0,0,0,0,11,161,0,25,0,0,0,0,10,165,3,79,0,0,0,0,10,10,4,59],[0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75,0,0,10,188,0,0,65,61],[0,0,0,0,9,7,0,75,0,0,10,211,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,5,133,3,79],[0,0,0,0,8,129,0,25,0,0,0,3,7,112,2,16,0,0,0,0,9,8,4,51,0,0,0,0,9,121,1,207],[0,0,0,0,9,121,2,47,0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47],[0,0,0,0,5,117,1,207,0,0,0,0,5,149,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,2,4,51,0,0,0,0,5,4,0,75,0,0,10,224,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,7,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,37,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,7,69,0,75,0,0,10,217,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,49,0,73,0,0,0,32,2,16,0,138],[0,0,0,0,0,35,4,53,0,0,0,31,1,16,0,57,0,0,0,10,2,16,1,127,0,0,0,0,1,50,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,4,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,7,155,1,0,0,65,0,0,7,155,2,96,0,156,0,0,0,0,6,1,128,25,0,0,0,64,2,96,2,16],[0,0,0,0,3,3,4,51,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16],[0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57],[30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,12,3,0,0,41,0,0,0,13,2,0,0,41],[0,0,0,159,0,0,97,61,0,13,0,0,0,2,0,29,0,0,0,1,2,0,3,103,0,12,0,0,0,3,0,29],[0,0,0,0,3,50,3,79,0,0,0,0,1,1,4,59,0,11,0,0,0,1,0,29,0,0,0,0,1,3,4,59],[0,0,0,113,3,16,0,140,0,0,13,34,0,0,193,61,0,0,0,12,9,0,0,41,0,0,1,224,1,144,0,57],[0,0,0,0,3,18,3,79,0,0,0,0,1,0,0,49,0,0,0,13,4,16,0,106,0,0,0,35,4,64,0,138],[0,0,0,0,3,3,4,59,0,0,7,160,5,0,0,65,0,0,0,0,6,67,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,7,160,4,64,1,151,0,0,7,160,7,48,1,151,0,0,0,0,8,71,0,75],[0,0,0,0,5,0,128,25,0,0,0,0,4,71,1,63,0,0,7,160,4,64,0,156,0,0,0,0,5,6,192,25],[0,0,0,0,4,5,0,75,0,0,0,159,0,0,193,61,0,0,0,0,3,147,0,25,0,0,0,0,2,50,3,79],[0,0,0,0,2,2,4,59,0,0,7,159,4,32,0,156,0,0,0,159,0,0,33,61,0,0,0,0,4,33,0,73],[0,0,0,32,1,48,0,57,0,0,7,160,3,0,0,65,0,0,0,0,5,65,0,75,0,0,0,0,5,0,0,25],[0,0,0,0,5,3,32,25,0,0,7,160,4,64,1,151,0,0,7,160,6,16,1,151,0,0,0,0,7,70,0,75],[0,0,0,0,3,0,128,25,0,0,0,0,4,70,1,63,0,0,7,160,4,64,0,156,0,0,0,0,3,5,192,25],[0,0,0,0,3,3,0,75,0,0,0,159,0,0,193,61,30,104,29,198,0,0,4,15,0,0,0,64,2,0,4,61],[0,0,0,64,3,32,0,57,0,0,0,0,0,19,4,53,0,0,0,64,1,0,0,57,0,0,0,0,1,18,4,54],[0,0,0,11,3,0,0,41,0,0,0,0,0,49,4,53,0,0,7,197,3,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,96,3,32,0,57,0,0,0,64,0,48,4,63,0,0,7,155,3,0,0,65,0,0,7,155,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,64,1,16,2,16,0,0,0,0,2,2,4,51,0,0,7,155,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,96,2,32,2,16,0,0,0,0,1,18,1,159,0,0,0,0,2,0,4,20],[0,0,7,155,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,159,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,64,2,0,4,61,0,0,0,32,3,32,0,57],[0,0,0,11,4,0,0,41,0,0,0,0,0,67,4,53,0,0,0,0,0,18,4,53,0,0,7,155,1,0,0,65],[0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,7,198,1,16,1,199],[0,0,30,105,0,1,4,46,0,0,7,155,1,16,1,151,0,0,0,0,1,19,3,79,0,0,0,0,2,82,0,73],[0,0,7,155,2,32,1,151,0,0,0,0,1,33,3,223,0,0,0,192,2,64,2,16,0,0,7,177,2,32,1,151],[0,0,7,178,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,30,104,30,99,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,7,155,4,48,1,151,0,0,0,1,2,32,1,144],[0,0,12,147,0,0,97,61,0,0,0,63,2,64,0,57,0,0,7,179,2,32,1,151,0,0,0,64,5,0,4,61],[0,0,0,0,2,37,0,25,0,0,0,0,3,82,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,0,7,159,6,32,0,156,0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,32,4,63,0,0,0,0,2,69,4,54,0,0,0,1,3,0,3,103,0,0,0,31,6,64,0,57],[0,0,0,5,6,96,2,114,0,0,11,140,0,0,97,61,0,0,0,0,7,48,3,104,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,146,0,25,0,0,0,0,9,151,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,104,0,75,0,0,11,132,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,11,142,0,0,97,61,0,0,0,31,6,64,1,143,0,0,0,5,4,64,2,114],[0,0,11,154,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,130,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,71,0,75,0,0,11,146,0,0,65,61,0,0,0,0,7,6,0,75,0,0,11,169,0,0,97,61],[0,0,0,5,4,64,2,16,0,0,0,0,1,65,3,79,0,0,0,0,4,66,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,7,4,4,51,0,0,0,0,7,103,1,207,0,0,0,0,7,103,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,1,97,2,47,0,0,0,0,1,97,1,207,0,0,0,0,1,113,1,159],[0,0,0,0,0,20,4,53,0,0,0,0,1,5,4,51,0,0,0,32,1,16,0,140,0,0,12,89,0,0,193,61],[0,0,0,13,11,0,0,41,0,0,0,100,1,176,0,57,0,0,0,0,1,19,3,79,0,0,0,68,4,176,0,57],[0,0,0,0,5,67,3,79,0,0,0,36,4,176,0,57,0,0,0,0,4,67,3,79,0,0,1,36,6,176,0,57],[0,0,0,0,6,99,3,79,0,0,1,4,7,176,0,57,0,0,0,0,7,115,3,79,0,0,0,228,8,176,0,57],[0,0,0,0,8,131,3,79,0,0,0,196,9,176,0,57,0,0,0,0,9,147,3,79,0,0,0,164,10,176,0,57],[0,0,0,0,10,163,3,79,0,0,0,132,11,176,0,57,0,0,0,0,11,179,3,79,0,0,0,12,3,48,3,96],[0,0,0,0,3,3,4,59,0,0,0,0,4,4,4,59,0,0,0,0,5,5,4,59,0,0,0,0,12,1,4,59],[0,0,0,0,11,11,4,59,0,0,0,0,10,10,4,59,0,0,0,0,9,9,4,59,0,0,0,0,8,8,4,59],[0,0,0,0,7,7,4,59,0,0,0,0,6,6,4,59,0,0,0,0,2,2,4,51,0,0,0,64,1,0,4,61],[0,0,1,192,13,16,0,57,0,0,0,0,0,45,4,53,0,0,1,160,2,16,0,57,0,0,0,11,13,0,0,41],[0,0,0,0,0,210,4,53,0,0,1,128,2,16,0,57,0,0,0,10,13,0,0,41,0,0,0,0,0,210,4,53],[0,0,1,96,2,16,0,57,0,0,0,0,0,98,4,53,0,0,1,64,2,16,0,57,0,0,0,0,0,114,4,53],[0,0,1,32,2,16,0,57,0,0,0,0,0,130,4,53,0,0,1,0,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,224,2,16,0,57,0,0,0,0,0,162,4,53,0,0,0,192,2,16,0,57,0,0,0,0,0,178,4,53],[0,0,0,160,2,16,0,57,0,0,0,0,0,194,4,53,0,0,0,128,2,16,0,57,0,0,0,0,0,82,4,53],[0,0,0,96,2,16,0,57,0,0,0,0,0,66,4,53,0,0,0,64,2,16,0,57,0,0,0,0,0,50,4,53],[0,0,0,32,2,16,0,57,0,0,7,183,3,0,0,65,0,0,0,0,0,50,4,53,0,0,1,192,3,0,0,57],[0,0,0,0,0,49,4,53,0,0,7,184,3,16,0,156,0,0,1,89,0,0,33,61,0,0,1,224,3,16,0,57],[0,0,0,64,0,48,4,63,0,0,7,155,4,0,0,65,0,0,7,155,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,7,155,3,16,0,156,0,0,0,0,1,4,128,25],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,7,175,1,16,1,199],[0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61],[0,0,0,0,1,1,4,59,0,10,0,0,0,1,0,29,0,0,0,64,1,0,4,61,0,11,0,0,0,1,0,29],[0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,0,0,1,0,4,20,0,0,7,155,2,16,0,156],[0,0,7,155,1,0,128,65,0,0,0,192,1,16,2,16,0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57],[30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61,0,0,0,11,4,0,0,41],[0,0,0,32,2,64,0,57,0,0,0,0,1,1,4,59,0,0,7,185,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,128,3,64,0,57,0,0,0,0,0,19,4,53,0,0,0,96,1,64,0,57,0,0,7,186,3,0,0,65],[0,0,0,0,0,49,4,53,0,0,0,64,1,64,0,57,0,0,7,187,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,128,1,0,0,57,0,0,0,0,0,20,4,53,0,0,7,188,1,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,11,4,0,0,41,0,0,0,160,1,64,0,57,0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65],[0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,2,32,2,16,0,0,0,0,3,4,4,51],[0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159],[0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16],[0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61,0,0,0,0,3,1,4,59,0,0,0,64,1,0,4,61],[0,0,0,66,2,16,0,57,0,0,0,10,4,0,0,41,0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57],[0,0,7,189,4,0,0,65,0,0,0,0,0,66,4,53,0,0,0,34,4,16,0,57,0,0,0,0,0,52,4,53],[0,0,0,66,3,0,0,57,0,0,0,0,0,49,4,53,0,0,7,190,3,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,128,3,16,0,57,0,0,0,64,0,48,4,63,0,0,7,155,3,0,0,65,0,0,7,155,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,7,155,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,7,155,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,10,254,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,7,181,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,7,161,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,7,155,2,0,0,65,0,0,7,155,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,7,182,1,16,1,199,0,0,30,106,0,1,4,48,0,0,0,56,8,64,0,140],[0,0,12,214,0,0,65,61,0,0,0,32,9,64,2,112,0,0,7,155,8,64,0,156,0,0,0,0,9,4,160,25],[0,0,7,155,8,64,0,156,0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191],[0,0,255,255,11,144,0,140,0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25],[0,0,0,255,9,160,0,140,0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57,0,0,7,166,10,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,0,8,152,1,159,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63],[0,0,0,0,10,33,3,79,0,0,0,2,9,128,0,58,0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80],[0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61,0,0,7,167,10,160,1,151],[0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159,0,0,7,171,10,160,1,199,0,0,0,0,0,169,4,53],[0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95,0,0,0,0,8,132,1,207,0,0,0,33,9,112,0,57],[0,0,0,0,0,137,4,53,0,0,0,0,8,7,0,25,0,0,12,231,0,0,1,61,0,0,0,31,3,64,1,143],[0,0,0,5,2,64,2,114,0,0,12,158,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16],[0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57],[0,0,0,0,6,37,0,75,0,0,12,151,0,0,65,61,0,0,0,0,5,3,0,75,0,0,12,172,0,0,97,61],[0,0,0,3,3,48,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137],[0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53],[0,0,0,96,1,64,2,16,0,0,30,106,0,1,4,48,0,0,0,56,8,64,0,140,0,0,13,118,0,0,65,61],[0,0,0,32,9,64,2,112,0,0,7,155,8,64,0,156,0,0,0,0,9,4,160,25,0,0,7,155,8,64,0,156],[0,0,0,0,10,0,0,25,0,0,0,4,10,0,32,57,0,0,0,2,8,160,1,191,0,0,255,255,11,144,0,140],[0,0,0,0,8,10,160,25,0,0,0,16,10,144,2,112,0,0,0,0,10,9,160,25,0,0,0,255,9,160,0,140],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,32,57,0,0,7,166,10,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,8,152,1,159,0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79],[0,0,0,2,9,128,0,58,0,0,0,0,9,150,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59],[0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16],[0,0,0,0,10,171,1,159,0,0,7,171,10,160,1,199,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16],[0,0,0,248,8,128,1,95,0,0,0,0,8,132,1,207,0,0,0,33,9,96,0,57,0,0,0,0,0,137,4,53],[0,0,0,0,8,6,0,25,0,0,13,135,0,0,1,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,135,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,10,64,2,16,0,0,7,167,9,144,1,151,0,0,0,0,9,169,1,159],[0,0,7,160,9,144,1,103,0,0,0,0,0,152,4,53,0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61],[0,0,7,166,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63],[0,0,0,0,2,33,3,79,0,0,0,1,12,0,0,58,0,0,0,0,9,199,4,54,0,0,0,0,2,32,3,80],[0,0,0,0,11,2,4,59,0,0,0,0,0,185,4,53,0,0,1,193,0,0,97,61,0,0,7,167,2,176,1,151],[0,0,7,172,10,32,1,199,0,0,0,0,0,169,4,53,0,0,0,0,9,6,4,51,0,0,0,0,9,73,0,25],[0,0,0,0,10,8,4,51,0,0,0,0,9,169,0,25,0,0,0,0,10,7,4,51,0,0,0,0,9,169,0,25],[0,0,0,64,10,0,4,61,0,0,7,159,9,144,1,151,0,0,0,56,13,144,0,140,0,0,14,30,0,0,65,61],[0,0,0,32,13,144,2,112,0,0,7,155,12,144,0,156,0,0,0,0,13,9,160,25,0,0,7,155,12,144,0,156],[0,0,0,0,14,0,0,25,0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140],[0,0,0,0,12,14,160,25,0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,32,57,0,0,7,166,14,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,12,220,1,159,0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57],[0,0,0,0,0,189,4,53,0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,192,2,16,0,0,0,0,2,43,1,159,0,0,7,173,2,32,1,199,0,0,0,0,0,45,4,53],[0,0,0,3,2,192,2,16,0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57],[0,0,0,0,0,41,4,53,0,0,14,43,0,0,1,61,0,0,0,0,3,1,0,75,0,0,13,194,0,0,193,61],[0,0,0,64,1,0,4,61,0,10,0,0,0,1,0,29,0,0,0,12,1,0,0,41,0,0,1,0,4,16,0,57],[0,0,0,0,1,66,3,79,0,0,0,0,3,1,4,59,0,0,0,128,1,48,0,140,0,0,14,144,0,0,65,61],[0,0,0,128,1,48,2,112,0,0,7,168,5,48,0,156,0,0,0,0,1,3,160,25,0,0,7,168,5,48,0,156],[0,0,0,0,5,0,0,25,0,0,0,16,5,0,32,57,0,0,0,8,6,80,1,191,0,0,7,159,7,16,0,156],[0,0,0,0,6,5,160,25,0,0,0,64,5,16,2,112,0,0,7,159,7,16,0,156,0,0,0,0,5,1,160,25],[0,0,0,4,1,96,1,191,0,0,7,155,7,80,0,156,0,0,0,0,1,6,160,25,0,0,0,32,6,80,2,112],[0,0,7,155,7,80,0,156,0,0,0,0,6,5,160,25,0,0,0,2,5,16,1,191,0,0,255,255,7,96,0,140],[0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140],[0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,6,80,0,57,0,0,0,0,1,22,1,111],[0,0,0,10,1,16,0,41,0,0,0,10,6,16,0,108,0,0,0,0,6,0,0,25,0,0,0,1,6,0,64,57],[0,0,7,159,7,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,6,96,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,10,6,0,0,41,0,0,0,0,6,22,4,54],[0,0,0,0,1,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114,0,0,13,98,0,0,97,61],[0,0,0,0,8,18,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25],[0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57],[0,0,0,0,10,121,0,75,0,0,13,90,0,0,65,61,0,0,0,0,7,0,0,75,0,0,13,100,0,0,97,61],[0,0,0,10,7,0,0,41,0,0,0,0,7,7,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,3,83,1,207,0,0,0,255,5,80,0,140,0,0,0,0,3,0,32,25,0,0,0,10,5,0,0,41],[0,0,0,33,5,80,0,57,0,0,14,164,0,0,1,61,0,0,7,166,8,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,96,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58],[0,0,0,0,8,134,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,10,64,2,16,0,0,7,167,9,144,1,151,0,0,0,0,9,169,1,159],[0,0,7,160,9,144,1,103,0,0,0,0,0,152,4,53,0,0,0,0,8,6,0,25,0,0,0,64,6,0,4,61],[0,0,7,166,9,96,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,96,0,57,0,0,0,64,0,144,4,63],[0,0,0,0,2,33,3,79,0,0,0,1,12,0,0,58,0,0,0,0,9,198,4,54,0,0,0,0,2,32,3,80],[0,0,0,0,11,2,4,59,0,0,0,0,0,185,4,53,0,0,1,193,0,0,97,61,0,0,7,167,2,176,1,151],[0,0,7,172,10,32,1,199,0,0,0,0,0,169,4,53,0,0,0,0,9,7,4,51,0,0,0,0,9,73,0,25],[0,0,0,0,10,8,4,51,0,0,0,0,9,169,0,25,0,0,0,0,10,6,4,51,0,0,0,0,9,169,0,25],[0,0,0,64,10,0,4,61,0,0,7,159,9,144,1,151,0,0,0,56,13,144,0,140,0,0,15,77,0,0,65,61],[0,0,0,32,13,144,2,112,0,0,7,155,12,144,0,156,0,0,0,0,13,9,160,25,0,0,7,155,12,144,0,156],[0,0,0,0,14,0,0,25,0,0,0,4,14,0,32,57,0,0,0,2,12,224,1,191,0,0,255,255,15,208,0,140],[0,0,0,0,12,14,160,25,0,0,0,16,14,208,2,112,0,0,0,0,14,13,160,25,0,0,0,255,13,224,0,140],[0,0,0,0,13,0,0,25,0,0,0,1,13,0,32,57,0,0,7,166,14,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,12,220,1,159,0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57],[0,0,0,0,0,189,4,53,0,0,0,2,11,192,0,58,0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,192,2,16,0,0,0,0,2,43,1,159,0,0,7,173,2,32,1,199,0,0,0,0,0,45,4,53],[0,0,0,3,2,192,2,16,0,0,0,248,2,32,1,95,0,0,0,0,2,41,1,207,0,0,0,33,9,160,0,57],[0,0,0,0,0,41,4,53,0,0,15,90,0,0,1,61,0,0,0,2,2,16,0,140,0,0,14,241,0,0,193,61],[0,0,0,0,1,0,4,21,0,10,0,0,0,1,0,29,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57],[0,0,7,155,1,0,0,65,0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59],[0,0,0,128,1,64,0,140,0,0,15,208,0,0,65,61,0,0,0,128,1,64,2,112,0,0,7,168,2,64,0,156],[0,0,0,0,1,4,160,25,0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57],[0,0,0,8,5,32,1,191,0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112],[0,0,7,159,6,16,0,156,0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,7,155,6,32,0,156],[0,0,0,0,1,5,160,25,0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,6,2,160,25],[0,0,0,2,5,16,1,191,0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112],[0,0,0,0,1,6,160,25,0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138],[0,0,0,65,2,80,0,57,0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57],[0,0,0,0,6,19,4,54,0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57],[0,0,0,5,7,112,2,114,0,0,14,12,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25],[0,0,0,5,10,144,2,16,0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59],[0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,14,4,0,0,65,61],[0,0,0,0,7,0,0,75,0,0,14,14,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16],[0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16],[0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25],[0,0,0,33,5,48,0,57,0,0,15,227,0,0,1,61,0,0,7,166,13,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,13,160,0,57,0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53],[0,0,0,0,0,202,4,53,0,0,0,0,11,12,0,75,0,0,1,193,0,0,97,61,0,0,0,248,9,144,2,16],[0,0,0,0,2,41,1,159,0,0,7,172,2,32,0,65,0,0,0,0,0,45,4,53,0,0,0,64,2,0,4,61],[0,0,0,32,9,32,0,57,0,0,7,174,11,0,0,65,0,0,0,0,0,185,4,53,0,0,0,33,11,32,0,57],[0,0,0,0,12,10,4,51,0,0,0,0,13,12,0,75,0,0,14,59,0,0,97,61,0,0,0,0,13,0,0,25],[0,0,0,0,14,189,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25,0,0,0,0,15,15,4,51],[0,0,0,0,0,254,4,53,0,0,0,0,14,205,0,75,0,0,14,52,0,0,65,61,0,0,0,0,10,188,0,25],[0,0,0,0,0,10,4,53,0,0,0,0,11,6,4,51,0,0,0,0,12,11,0,75,0,0,14,72,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,108,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,14,65,0,0,65,61],[0,0,0,0,6,171,0,25,0,0,0,0,0,6,4,53,0,0,0,0,10,8,4,51,0,0,0,0,11,10,0,75],[0,0,14,85,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,107,0,25,0,0,0,32,11,176,0,57],[0,0,0,0,13,139,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75],[0,0,14,78,0,0,65,61,0,0,0,0,5,81,3,79,0,0,0,0,1,106,0,25,0,0,0,31,6,64,1,143],[0,0,0,0,0,1,4,53,0,0,0,5,8,64,2,114,0,0,14,100,0,0,97,61,0,0,0,0,10,0,0,25],[0,0,0,5,11,160,2,16,0,0,0,0,12,177,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59],[0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,14,92,0,0,65,61],[0,0,0,0,10,6,0,75,0,0,14,115,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,5,133,3,79],[0,0,0,0,8,129,0,25,0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,106,1,207],[0,0,0,0,10,106,2,47,0,0,0,0,5,5,4,59,0,0,1,0,6,96,0,137,0,0,0,0,5,101,2,47],[0,0,0,0,5,101,1,207,0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,7,4,51,0,0,0,0,5,4,0,75,0,0,14,128,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,117,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,14,121,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,33,0,73,0,0,0,32,4,16,0,138],[0,0,0,0,0,66,4,53,0,0,0,31,1,16,0,57,0,0,0,0,3,49,1,111,0,0,0,0,1,35,0,25],[0,0,0,0,3,49,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,4,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144,0,0,15,190,0,0,97,61,0,0,1,89,0,0,1,61],[0,0,0,10,1,0,0,41,0,0,7,166,1,16,0,156,0,0,1,89,0,0,33,61,0,0,0,10,5,0,0,41],[0,0,0,64,1,80,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58,0,0,0,0,5,21,4,54],[0,0,0,0,1,0,0,49,0,0,0,0,6,18,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,48,2,16,0,0,7,160,8,0,0,65],[0,0,0,0,3,3,0,75,0,0,0,0,8,7,192,25,0,0,7,167,3,96,1,151,0,0,0,0,3,131,1,159],[0,0,0,0,0,53,4,53,0,0,0,64,3,0,4,61,0,0,0,96,4,64,0,138,0,0,0,0,5,66,3,79],[0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140,0,0,16,49,0,0,65,61,0,0,0,128,6,80,2,112],[0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25,0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25],[0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25],[0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191],[0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156],[0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25],[0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57],[0,0,0,32,7,0,0,138,0,0,0,65,8,96,0,57,0,0,0,0,7,120,1,111,0,0,0,0,7,115,0,25],[0,0,0,0,8,55,0,75,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63],[0,0,0,2,7,96,0,57,0,0,0,0,7,115,4,54,0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114],[0,0,14,223,0,0,97,61,0,0,0,0,9,18,3,79,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,14,215,0,0,65,61,0,0,0,0,8,0,0,75],[0,0,14,225,0,0,97,61,0,0,0,0,8,3,4,51,0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,8,7,4,51,0,0,7,167,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159],[0,0,7,169,8,128,0,65,0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137],[0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140,0,0,0,0,5,0,32,25,0,0,0,33,6,48,0,57],[0,0,16,66,0,0,1,61,0,0,0,1,1,16,0,140,0,0,15,201,0,0,193,61,0,0,0,0,1,0,4,21],[0,10,0,0,0,1,0,29,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,24,107,0,0,97,61,0,0,0,64,3,0,4,61,0,0,0,0,4,1,4,59,0,0,0,128,1,64,0,140],[0,0,16,143,0,0,65,61,0,0,0,128,1,64,2,112,0,0,7,168,2,64,0,156,0,0,0,0,1,4,160,25],[0,0,7,168,2,64,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,5,32,1,191],[0,0,7,159,6,16,0,156,0,0,0,0,5,2,160,25,0,0,0,64,2,16,2,112,0,0,7,159,6,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,80,1,191,0,0,7,155,6,32,0,156,0,0,0,0,1,5,160,25],[0,0,0,32,6,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,6,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,96,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,96,2,112,0,0,0,0,1,6,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,32,1,0,0,138,0,0,0,65,2,80,0,57],[0,0,0,0,1,18,1,111,0,0,0,0,1,19,0,25,0,0,0,0,2,49,0,75,0,0,0,0,2,0,0,25],[0,0,0,1,2,0,64,57,0,0,7,159,6,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,0,2,1,80,0,57,0,0,0,0,6,19,4,54],[0,0,0,1,1,0,3,103,0,0,0,0,2,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,15,59,0,0,97,61,0,0,0,0,8,33,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,15,51,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,15,61,0,0,97,61,0,0,0,0,7,3,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25,0,0,0,33,5,48,0,57],[0,0,16,162,0,0,1,61,0,0,7,166,13,160,0,156,0,0,1,89,0,0,33,61,0,0,0,64,13,160,0,57],[0,0,0,64,0,208,4,63,0,0,0,32,13,160,0,57,0,0,0,0,0,189,4,53,0,0,0,0,0,202,4,53],[0,0,0,0,11,12,0,75,0,0,1,193,0,0,97,61,0,0,0,248,9,144,2,16,0,0,0,0,2,41,1,159],[0,0,7,172,2,32,0,65,0,0,0,0,0,45,4,53,0,0,0,64,2,0,4,61,0,0,0,32,9,32,0,57],[0,0,7,175,11,0,0,65,0,0,0,0,0,185,4,53,0,0,0,33,11,32,0,57,0,0,0,0,12,10,4,51],[0,0,0,0,13,12,0,75,0,0,15,106,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,0,14,189,0,25],[0,0,0,32,13,208,0,57,0,0,0,0,15,173,0,25,0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53],[0,0,0,0,14,205,0,75,0,0,15,99,0,0,65,61,0,0,0,0,10,188,0,25,0,0,0,0,0,10,4,53],[0,0,0,0,11,7,4,51,0,0,0,0,12,11,0,75,0,0,15,119,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,124,0,25,0,0,0,0,14,14,4,51],[0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,15,112,0,0,65,61,0,0,0,0,7,171,0,25],[0,0,0,0,0,7,4,53,0,0,0,0,10,8,4,51,0,0,0,0,11,10,0,75,0,0,15,132,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,12,123,0,25,0,0,0,32,11,176,0,57,0,0,0,0,13,139,0,25],[0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75,0,0,15,125,0,0,65,61],[0,0,0,0,5,81,3,79,0,0,0,0,1,122,0,25,0,0,0,31,7,64,1,143,0,0,0,0,0,1,4,53],[0,0,0,5,8,64,2,114,0,0,15,147,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16],[0,0,0,0,12,177,0,25,0,0,0,0,11,181,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53],[0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,15,139,0,0,65,61,0,0,0,0,10,7,0,75],[0,0,15,162,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,5,133,3,79,0,0,0,0,8,129,0,25],[0,0,0,3,7,112,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,122,1,207,0,0,0,0,10,122,2,47],[0,0,0,0,5,5,4,59,0,0,1,0,7,112,0,137,0,0,0,0,5,117,2,47,0,0,0,0,5,117,1,207],[0,0,0,0,5,165,1,159,0,0,0,0,0,88,4,53,0,0,0,0,1,65,0,25,0,0,0,0,0,1,4,53],[0,0,0,0,4,6,4,51,0,0,0,0,5,4,0,75,0,0,15,175,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,7,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,101,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,135,4,53,0,0,0,0,7,69,0,75,0,0,15,168,0,0,65,61,0,0,0,0,1,20,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,1,33,0,73,0,0,0,32,4,16,0,138,0,0,0,0,0,66,4,53],[0,0,0,31,1,16,0,57,0,0,0,0,3,49,1,111,0,0,0,0,1,35,0,25,0,0,0,0,3,49,0,75],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57,0,0,7,159,4,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,3,48,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65],[0,0,7,155,3,144,0,156,0,0,0,0,9,1,128,25,0,0,0,64,3,144,2,16,0,0,0,0,2,2,4,51],[0,0,7,155,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159],[0,0,10,249,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,7,193,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,19,3,0,0,57,0,0,12,95,0,0,1,61],[0,0,7,166,1,48,0,156,0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63],[0,0,0,1,1,0,0,58,0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103],[0,0,0,0,6,33,3,79,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75],[0,0,0,0,8,7,192,25,0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53],[0,0,0,64,5,0,4,61,0,0,0,13,4,0,0,41,0,0,1,4,4,64,0,57,0,0,0,0,6,65,3,79],[0,0,0,0,6,6,4,59,0,0,0,128,7,96,0,140,0,0,16,240,0,0,65,61,0,0,0,128,7,96,2,112],[0,0,7,168,8,96,0,156,0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25],[0,0,0,16,8,0,32,57,0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,64,8,112,2,112,0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191],[0,0,7,155,7,128,0,156,0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156],[0,0,0,0,9,8,160,25,0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25],[0,0,0,16,8,144,2,112,0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57],[0,0,0,32,8,0,0,138,0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,133,0,25],[0,0,0,0,9,88,0,75,0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63],[0,0,0,2,8,112,0,57,0,0,0,0,8,133,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114],[0,0,16,31,0,0,97,61,0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16],[0,0,0,0,13,200,0,25,0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53],[0,0,0,1,11,176,0,57,0,0,0,0,12,155,0,75,0,0,16,23,0,0,65,61,0,0,0,0,9,0,0,75],[0,0,16,33,0,0,97,61,0,0,0,0,9,5,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,9,8,4,51,0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159],[0,0,7,169,9,144,0,65,0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137],[0,0,0,0,6,118,1,207,0,0,0,255,7,112,0,140,0,0,0,0,6,0,32,25,0,0,0,33,7,80,0,57],[0,0,17,1,0,0,1,61,0,0,7,166,6,48,0,156,0,0,1,89,0,0,33,61,0,0,0,64,6,48,0,57],[0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79,0,0,0,1,6,0,0,58,0,0,0,0,6,99,4,54],[0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75,0,0,0,0,9,8,192,25],[0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53,0,0,0,64,4,64,0,138],[0,0,0,0,5,66,3,79,0,0,0,64,4,0,4,61,0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140],[0,0,17,78,0,0,65,61,0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191],[0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156],[0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191],[0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25],[0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,32,7,0,0,138,0,0,0,65,8,96,0,57],[0,0,0,0,7,120,1,111,0,0,0,0,7,116,0,25,0,0,0,0,8,71,0,75,0,0,0,0,8,0,0,25],[0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57,0,0,0,0,7,116,4,54],[0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,16,125,0,0,97,61,0,0,0,0,9,18,3,79],[0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79],[0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75],[0,0,16,117,0,0,65,61,0,0,0,0,8,0,0,75,0,0,16,127,0,0,97,61,0,0,0,0,8,4,4,51],[0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61,0,0,0,0,8,7,4,51,0,0,7,167,8,128,1,151],[0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,169,8,128,0,65,0,0,0,0,0,135,4,53],[0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140],[0,0,0,0,5,0,32,25,0,0,0,33,6,64,0,57,0,0,17,95,0,0,1,61,0,0,7,166,1,48,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,1,48,0,57,0,0,0,64,0,16,4,63,0,0,0,1,1,0,0,58],[0,0,0,0,5,19,4,54,0,0,0,0,2,0,0,49,0,0,0,1,1,0,3,103,0,0,0,0,6,33,3,79],[0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59,0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65,0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25],[0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159,0,0,0,0,0,69,4,53,0,0,0,64,5,0,4,61],[0,0,0,13,4,0,0,41,0,0,1,4,4,64,0,57,0,0,0,0,6,65,3,79,0,0,0,0,6,6,4,59],[0,0,0,128,7,96,0,140,0,0,17,239,0,0,65,61,0,0,0,128,7,96,2,112,0,0,7,168,8,96,0,156],[0,0,0,0,7,6,160,25,0,0,7,168,8,96,0,156,0,0,0,0,8,0,0,25,0,0,0,16,8,0,32,57],[0,0,0,8,9,128,1,191,0,0,7,159,10,112,0,156,0,0,0,0,9,8,160,25,0,0,0,64,8,112,2,112],[0,0,7,159,10,112,0,156,0,0,0,0,8,7,160,25,0,0,0,4,10,144,1,191,0,0,7,155,7,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,32,9,128,2,112,0,0,7,155,7,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,2,7,160,1,191,0,0,255,255,8,144,0,140,0,0,0,0,7,10,160,25,0,0,0,16,8,144,2,112],[0,0,0,0,8,9,160,25,0,0,0,255,8,128,0,140,0,0,0,1,7,112,32,57,0,0,0,32,8,0,0,138],[0,0,0,65,9,112,0,57,0,0,0,0,8,137,1,111,0,0,0,0,8,133,0,25,0,0,0,0,9,88,0,75],[0,0,0,0,9,0,0,25,0,0,0,1,9,0,64,57,0,0,7,159,10,128,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,9,144,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,128,4,63,0,0,0,2,8,112,0,57],[0,0,0,0,8,133,4,54,0,0,0,33,9,112,0,57,0,0,0,5,9,144,2,114,0,0,16,222,0,0,97,61],[0,0,0,0,10,33,3,79,0,0,0,0,11,0,0,25,0,0,0,5,12,176,2,16,0,0,0,0,13,200,0,25],[0,0,0,0,12,202,3,79,0,0,0,0,12,12,4,59,0,0,0,0,0,205,4,53,0,0,0,1,11,176,0,57],[0,0,0,0,12,155,0,75,0,0,16,214,0,0,65,61,0,0,0,0,9,0,0,75,0,0,16,224,0,0,97,61],[0,0,0,0,9,5,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,8,4,51],[0,0,7,167,9,144,1,151,0,0,0,248,10,112,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65],[0,0,0,0,0,152,4,53,0,0,0,3,7,112,2,16,0,0,0,248,7,112,0,137,0,0,0,0,6,118,1,207],[0,0,0,255,7,112,0,140,0,0,0,0,6,0,32,25,0,0,0,33,7,80,0,57,0,0,18,0,0,0,1,61],[0,0,7,166,7,80,0,156,0,0,1,89,0,0,33,61,0,0,0,64,7,80,0,57,0,0,0,64,0,112,4,63],[0,0,0,0,8,33,3,79,0,0,0,1,7,0,0,58,0,0,0,0,7,117,4,54,0,0,0,0,8,128,3,80],[0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61,0,0,0,248,9,96,2,16],[0,0,7,160,10,0,0,65,0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151],[0,0,0,0,6,166,1,159,0,0,0,0,0,103,4,53,0,0,0,64,6,0,4,61,0,0,0,64,4,64,0,138],[0,0,0,0,7,65,3,79,0,0,0,0,7,7,4,59,0,0,0,128,8,112,0,140,0,0,18,77,0,0,65,61],[0,0,0,128,8,112,2,112,0,0,7,168,9,112,0,156,0,0,0,0,8,7,160,25,0,0,7,168,9,112,0,156],[0,0,0,0,9,0,0,25,0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191,0,0,7,159,11,128,0,156],[0,0,0,0,10,9,160,25,0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156,0,0,0,0,9,8,160,25],[0,0,0,4,11,160,1,191,0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112],[0,0,7,155,8,144,0,156,0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140],[0,0,0,0,8,11,160,25,0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140],[0,0,0,1,8,128,32,57,0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111],[0,0,0,0,9,150,0,25,0,0,0,0,10,105,0,75,0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57],[0,0,7,159,11,144,0,156,0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,144,4,63,0,0,0,2,9,128,0,57,0,0,0,0,9,150,4,54,0,0,0,33,10,128,0,57],[0,0,0,5,10,160,2,114,0,0,17,60,0,0,97,61,0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25],[0,0,0,5,13,192,2,16,0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59],[0,0,0,0,0,222,4,53,0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75,0,0,17,52,0,0,65,61],[0,0,0,0,10,0,0,75,0,0,17,62,0,0,97,61,0,0,0,0,10,6,4,51,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16],[0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16],[0,0,0,248,8,128,0,137,0,0,0,0,7,135,1,207,0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25],[0,0,0,33,8,96,0,57,0,0,18,94,0,0,1,61,0,0,7,166,6,64,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,6,64,0,57,0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79,0,0,0,1,6,0,0,58],[0,0,0,0,6,100,4,54,0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75],[0,0,0,0,9,8,192,25,0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53],[0,0,0,64,5,0,4,61,0,9,0,0,0,5,0,29,0,0,0,32,5,80,0,57,0,0,0,0,6,3,4,51],[0,0,0,0,7,6,0,75,0,0,17,110,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,0,8,87,0,25],[0,0,0,32,7,112,0,57,0,0,0,0,9,55,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,152,4,53],[0,0,0,0,8,103,0,75,0,0,17,103,0,0,65,61,0,0,0,0,3,86,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,5,4,4,51,0,0,0,0,6,5,0,75,0,0,17,123,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,8,70,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,135,4,53,0,0,0,0,7,86,0,75,0,0,17,116,0,0,65,61,0,0,0,0,3,53,0,25],[0,0,0,0,0,3,4,53,0,0,0,9,5,0,0,41,0,0,0,0,3,83,0,73,0,0,0,32,4,48,0,138],[0,0,0,0,0,69,4,53,0,0,0,31,3,48,0,57,0,7,0,32,0,0,0,146,0,0,0,7,3,48,1,127],[0,0,0,0,4,83,0,25,0,0,0,0,3,52,0,75,0,0,0,0,3,0,0,25,0,0,0,1,3,0,64,57],[0,8,0,0,0,4,0,29,0,0,7,159,4,64,0,156,0,0,1,89,0,0,33,61,0,0,0,1,3,48,1,144],[0,0,1,89,0,0,193,61,0,0,0,8,3,0,0,41,0,0,0,64,0,48,4,63,0,0,7,166,3,48,0,156],[0,0,1,89,0,0,33,61,0,0,0,13,6,0,0,41,0,0,0,68,3,96,0,57,0,0,0,0,3,50,3,79],[0,0,0,0,3,3,4,59,0,0,0,8,7,0,0,41,0,0,0,64,4,112,0,57,0,0,0,64,0,64,4,63],[0,0,0,32,4,112,0,57,0,0,7,170,5,0,0,65,0,0,0,0,0,84,4,53,0,0,0,21,4,0,0,57],[0,0,0,0,0,71,4,53,0,0,0,96,3,48,2,16,0,0,0,33,4,112,0,57,0,0,0,0,0,52,4,53],[0,0,1,36,3,96,0,57,0,0,0,0,4,50,3,79,0,0,0,64,5,0,4,61,0,6,0,0,0,5,0,29],[0,0,0,0,4,4,4,59,0,0,0,128,5,64,0,140,0,0,19,9,0,0,65,61,0,0,0,128,5,64,2,112],[0,0,7,168,6,64,0,156,0,0,0,0,5,4,160,25,0,0,7,168,6,64,0,156,0,0,0,0,6,0,0,25],[0,0,0,16,6,0,32,57,0,0,0,8,7,96,1,191,0,0,7,159,8,80,0,156,0,0,0,0,7,6,160,25],[0,0,0,64,6,80,2,112,0,0,7,159,8,80,0,156,0,0,0,0,6,5,160,25,0,0,0,4,8,112,1,191],[0,0,7,155,5,96,0,156,0,0,0,0,8,7,160,25,0,0,0,32,7,96,2,112,0,0,7,155,5,96,0,156],[0,0,0,0,7,6,160,25,0,0,0,2,5,128,1,191,0,0,255,255,6,112,0,140,0,0,0,0,5,8,160,25],[0,0,0,16,6,112,2,112,0,0,0,0,6,7,160,25,0,0,0,255,6,96,0,140,0,0,0,1,5,80,32,57],[0,0,0,65,6,80,0,57,0,0,0,7,6,96,1,127,0,0,0,6,6,96,0,41,0,0,0,6,7,96,0,108],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,64,57,0,0,7,159,8,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,7,112,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,96,4,63,0,0,0,2,6,80,0,57],[0,0,0,6,7,0,0,41,0,0,0,0,6,103,4,54,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,17,219,0,0,97,61,0,0,0,0,8,18,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,17,211,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,17,221,0,0,97,61,0,0,0,6,7,0,0,41,0,0,0,0,7,7,4,51,0,0,0,0,7,7,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16],[0,0,0,0,7,120,1,159,0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16],[0,0,0,248,5,80,0,137,0,0,0,0,4,84,1,207,0,0,0,255,5,80,0,140,0,0,0,0,4,0,32,25],[0,0,0,6,5,0,0,41,0,0,0,33,5,80,0,57,0,0,19,28,0,0,1,61,0,0,7,166,7,80,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,7,80,0,57,0,0,0,64,0,112,4,63,0,0,0,0,8,33,3,79],[0,0,0,1,7,0,0,58,0,0,0,0,7,117,4,54,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65],[0,0,0,0,6,6,0,75,0,0,0,0,10,9,192,25,0,0,7,167,6,128,1,151,0,0,0,0,6,166,1,159],[0,0,0,0,0,103,4,53,0,0,0,64,6,0,4,61,0,0,0,96,4,64,0,138,0,0,0,0,7,65,3,79],[0,0,0,0,7,7,4,59,0,0,0,128,8,112,0,140,0,0,18,171,0,0,65,61,0,0,0,128,8,112,2,112],[0,0,7,168,9,112,0,156,0,0,0,0,8,7,160,25,0,0,7,168,9,112,0,156,0,0,0,0,9,0,0,25],[0,0,0,16,9,0,32,57,0,0,0,8,10,144,1,191,0,0,7,159,11,128,0,156,0,0,0,0,10,9,160,25],[0,0,0,64,9,128,2,112,0,0,7,159,11,128,0,156,0,0,0,0,9,8,160,25,0,0,0,4,11,160,1,191],[0,0,7,155,8,144,0,156,0,0,0,0,11,10,160,25,0,0,0,32,10,144,2,112,0,0,7,155,8,144,0,156],[0,0,0,0,10,9,160,25,0,0,0,2,8,176,1,191,0,0,255,255,9,160,0,140,0,0,0,0,8,11,160,25],[0,0,0,16,9,160,2,112,0,0,0,0,9,10,160,25,0,0,0,255,9,144,0,140,0,0,0,1,8,128,32,57],[0,0,0,32,9,0,0,138,0,0,0,65,10,128,0,57,0,0,0,0,9,154,1,111,0,0,0,0,9,150,0,25],[0,0,0,0,10,105,0,75,0,0,0,0,10,0,0,25,0,0,0,1,10,0,64,57,0,0,7,159,11,144,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,10,160,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,144,4,63],[0,0,0,2,9,128,0,57,0,0,0,0,9,150,4,54,0,0,0,33,10,128,0,57,0,0,0,5,10,160,2,114],[0,0,18,59,0,0,97,61,0,0,0,0,11,33,3,79,0,0,0,0,12,0,0,25,0,0,0,5,13,192,2,16],[0,0,0,0,14,217,0,25,0,0,0,0,13,219,3,79,0,0,0,0,13,13,4,59,0,0,0,0,0,222,4,53],[0,0,0,1,12,192,0,57,0,0,0,0,13,172,0,75,0,0,18,51,0,0,65,61,0,0,0,0,10,0,0,75],[0,0,18,61,0,0,97,61,0,0,0,0,10,6,4,51,0,0,0,0,10,10,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,10,9,4,51,0,0,7,167,10,160,1,151,0,0,0,248,11,128,2,16,0,0,0,0,10,171,1,159],[0,0,7,169,10,160,0,65,0,0,0,0,0,169,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,0,137],[0,0,0,0,7,135,1,207,0,0,0,255,8,128,0,140,0,0,0,0,7,0,32,25,0,0,0,33,8,96,0,57],[0,0,18,188,0,0,1,61,0,0,7,166,8,96,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,96,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,134,4,54],[0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59,0,0,0,0,0,152,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,10,112,2,16,0,0,7,160,11,0,0,65,0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25],[0,0,7,167,7,144,1,151,0,0,0,0,7,183,1,159,0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61],[0,0,0,32,4,64,0,138,0,0,0,0,8,65,3,79,0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140],[0,0,19,99,0,0,65,61,0,0,0,128,9,128,2,112,0,0,7,168,10,128,0,156,0,0,0,0,9,8,160,25],[0,0,7,168,10,128,0,156,0,0,0,0,10,0,0,25,0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191],[0,0,7,159,12,144,0,156,0,0,0,0,11,10,160,25,0,0,0,64,10,144,2,112,0,0,7,159,12,144,0,156],[0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191,0,0,7,155,9,160,0,156,0,0,0,0,12,11,160,25],[0,0,0,32,11,160,2,112,0,0,7,155,9,160,0,156,0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191],[0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25,0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25],[0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57,0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57],[0,0,0,0,10,171,1,111,0,0,0,0,10,167,0,25,0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25],[0,0,0,1,11,0,64,57,0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61,0,0,0,1,11,176,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54],[0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114,0,0,18,153,0,0,97,61,0,0,0,0,12,33,3,79],[0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16,0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79],[0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53,0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75],[0,0,18,145,0,0,65,61,0,0,0,0,11,0,0,75,0,0,18,155,0,0,97,61,0,0,0,0,11,7,4,51],[0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,0,0,11,10,4,51,0,0,7,167,11,176,1,151],[0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159,0,0,7,169,11,176,0,65,0,0,0,0,0,186,4,53],[0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137,0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140],[0,0,0,0,8,0,32,25,0,0,0,33,9,112,0,57,0,0,19,116,0,0,1,61,0,0,7,166,8,96,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,8,96,0,57,0,0,0,64,0,128,4,63,0,0,0,0,9,33,3,79],[0,0,0,1,8,0,0,58,0,0,0,0,8,134,4,54,0,0,0,0,9,144,3,80,0,0,0,0,9,9,4,59],[0,0,0,0,0,152,4,53,0,0,1,193,0,0,97,61,0,0,0,248,10,112,2,16,0,0,7,160,11,0,0,65],[0,0,0,0,7,7,0,75,0,0,0,0,11,10,192,25,0,0,7,167,7,144,1,151,0,0,0,0,7,183,1,159],[0,0,0,0,0,120,4,53,0,0,0,64,7,0,4,61,0,0,0,64,4,64,0,138,0,0,0,0,8,65,3,79],[0,0,0,0,8,8,4,59,0,0,0,128,9,128,0,140,0,0,19,194,0,0,65,61,0,0,0,128,9,128,2,112],[0,0,7,168,10,128,0,156,0,0,0,0,9,8,160,25,0,0,7,168,10,128,0,156,0,0,0,0,10,0,0,25],[0,0,0,16,10,0,32,57,0,0,0,8,11,160,1,191,0,0,7,159,12,144,0,156,0,0,0,0,11,10,160,25],[0,0,0,64,10,144,2,112,0,0,7,159,12,144,0,156,0,0,0,0,10,9,160,25,0,0,0,4,12,176,1,191],[0,0,7,155,9,160,0,156,0,0,0,0,12,11,160,25,0,0,0,32,11,160,2,112,0,0,7,155,9,160,0,156],[0,0,0,0,11,10,160,25,0,0,0,2,9,192,1,191,0,0,255,255,10,176,0,140,0,0,0,0,9,12,160,25],[0,0,0,16,10,176,2,112,0,0,0,0,10,11,160,25,0,0,0,255,10,160,0,140,0,0,0,1,9,144,32,57],[0,0,0,32,10,0,0,138,0,0,0,65,11,144,0,57,0,0,0,0,10,171,1,111,0,0,0,0,10,167,0,25],[0,0,0,0,11,122,0,75,0,0,0,0,11,0,0,25,0,0,0,1,11,0,64,57,0,0,7,159,12,160,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,11,176,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63],[0,0,0,2,10,144,0,57,0,0,0,0,10,167,4,54,0,0,0,33,11,144,0,57,0,0,0,5,11,176,2,114],[0,0,18,247,0,0,97,61,0,0,0,0,12,33,3,79,0,0,0,0,13,0,0,25,0,0,0,5,14,208,2,16],[0,0,0,0,15,234,0,25,0,0,0,0,14,236,3,79,0,0,0,0,14,14,4,59,0,0,0,0,0,239,4,53],[0,0,0,1,13,208,0,57,0,0,0,0,14,189,0,75,0,0,18,239,0,0,65,61,0,0,0,0,11,0,0,75],[0,0,18,249,0,0,97,61,0,0,0,0,11,7,4,51,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,11,10,4,51,0,0,7,167,11,176,1,151,0,0,0,248,12,144,2,16,0,0,0,0,11,188,1,159],[0,0,7,169,11,176,0,65,0,0,0,0,0,186,4,53,0,0,0,3,9,144,2,16,0,0,0,248,9,144,0,137],[0,0,0,0,8,152,1,207,0,0,0,255,9,144,0,140,0,0,0,0,8,0,32,25,0,0,0,33,9,112,0,57],[0,0,19,211,0,0,1,61,0,0,0,6,5,0,0,41,0,0,7,166,5,80,0,156,0,0,1,89,0,0,33,61],[0,0,0,6,7,0,0,41,0,0,0,64,5,112,0,57,0,0,0,64,0,80,4,63,0,0,0,0,6,18,3,79],[0,0,0,1,5,0,0,58,0,0,0,0,5,87,4,54,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,101,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,64,2,16,0,0,7,160,8,0,0,65],[0,0,0,0,4,4,0,75,0,0,0,0,8,7,192,25,0,0,7,167,4,96,1,151,0,0,0,0,4,132,1,159],[0,0,0,0,0,69,4,53,0,0,0,12,10,0,0,41,0,0,0,0,6,161,0,73,0,0,0,160,4,48,0,57],[0,0,0,0,3,66,3,79,0,0,0,0,5,3,4,59,0,0,0,31,3,96,0,138,0,0,7,160,6,48,1,151],[0,0,7,160,7,80,1,151,0,0,7,160,8,0,0,65,0,0,0,0,9,103,0,75,0,0,0,0,9,0,0,25],[0,0,0,0,9,8,64,25,0,0,0,0,6,103,1,63,0,0,0,0,7,53,0,75,0,0,0,0,8,0,64,25],[0,0,7,160,6,96,0,156,0,0,0,0,9,8,192,25,0,0,0,0,6,9,0,75,0,0,0,159,0,0,193,61],[0,0,0,0,6,165,0,25,0,0,0,0,5,98,3,79,0,0,0,0,5,5,4,59,0,0,7,159,7,80,0,156],[0,0,0,159,0,0,33,61,0,0,0,0,7,81,0,73,0,0,0,32,6,96,0,57,0,0,7,160,8,0,0,65],[0,0,0,0,9,118,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,32,25,0,0,7,160,7,112,1,151],[0,0,7,160,10,96,1,151,0,0,0,0,11,122,0,75,0,0,0,0,8,0,128,25,0,0,0,0,7,122,1,63],[0,0,7,160,7,112,0,156,0,0,0,0,8,9,192,25,0,0,0,0,7,8,0,75,0,0,0,159,0,0,193,61],[0,0,0,1,7,80,0,140,0,0,21,96,0,0,193,61,0,0,0,0,5,98,3,79,0,0,0,0,5,5,4,59],[0,0,0,1,6,0,0,138,0,0,7,160,7,0,0,65,0,0,0,0,6,101,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,7,32,25,0,0,7,160,5,80,1,151,0,0,7,160,8,80,0,156,0,0,0,0,7,0,128,25],[0,0,7,160,5,80,1,103,0,0,7,160,5,80,0,156,0,0,0,0,7,6,192,25,0,5,0,96,0,0,0,61],[0,0,0,0,5,7,0,75,0,0,22,99,0,0,193,61,0,0,0,64,5,0,4,61,0,5,0,0,0,5,0,29],[0,0,7,166,5,80,0,156,0,0,1,89,0,0,33,61,0,0,0,5,7,0,0,41,0,0,0,64,5,112,0,57],[0,0,0,64,0,80,4,63,0,0,0,32,5,112,0,57,0,0,7,169,6,0,0,65,0,0,0,0,0,101,4,53],[0,0,0,1,5,0,0,57,0,0,0,0,0,87,4,53,0,0,22,99,0,0,1,61,0,0,7,166,9,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79],[0,0,0,1,9,0,0,58,0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59],[0,0,0,0,0,169,4,53,0,0,1,193,0,0,97,61,0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65],[0,0,0,0,8,8,0,75,0,0,0,0,12,11,192,25,0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159],[0,0,0,0,0,137,4,53,0,0,0,64,8,0,4,61,0,9,0,64,0,64,0,146,0,0,0,9,9,16,3,96],[0,0,0,0,9,9,4,59,0,0,0,128,10,144,0,140,0,0,20,51,0,0,65,61,0,0,0,128,10,144,2,112],[0,0,7,168,11,144,0,156,0,0,0,0,10,9,160,25,0,0,7,168,11,144,0,156,0,0,0,0,11,0,0,25],[0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156,0,0,0,0,12,11,160,25],[0,0,0,64,11,160,2,112,0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,13,192,1,191],[0,0,7,155,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140,0,0,0,0,10,13,160,25],[0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,10,160,32,57],[0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111,0,0,0,0,11,184,0,25],[0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57,0,0,7,159,13,176,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,176,4,63],[0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57,0,0,0,5,12,192,2,114],[0,0,19,175,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25,0,0,0,5,15,224,2,16],[0,0,0,0,4,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59,0,0,0,0,0,244,4,53],[0,0,0,1,14,224,0,57,0,0,0,0,4,206,0,75,0,0,19,167,0,0,65,61,0,0,0,0,4,0,0,75],[0,0,19,177,0,0,97,61,0,0,0,0,4,8,4,51,0,0,0,0,4,4,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,4,11,4,51,0,0,7,167,4,64,1,151,0,0,0,248,12,160,2,16,0,0,0,0,4,76,1,159],[0,0,7,169,4,64,0,65,0,0,0,0,0,75,4,53,0,0,0,3,4,160,2,16,0,0,0,248,4,64,0,137],[0,0,0,0,9,73,1,207,0,0,0,255,4,64,0,140,0,0,0,0,9,0,32,25,0,0,0,33,4,128,0,57],[0,0,0,0,0,148,4,53,0,0,20,69,0,0,1,61,0,0,7,166,9,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,9,112,0,57,0,0,0,64,0,144,4,63,0,0,0,0,10,33,3,79,0,0,0,1,9,0,0,58],[0,0,0,0,9,151,4,54,0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,169,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,11,128,2,16,0,0,7,160,12,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,12,11,192,25,0,0,7,167,8,160,1,151,0,0,0,0,8,200,1,159,0,0,0,0,0,137,4,53],[0,0,0,64,9,0,4,61,0,0,7,166,8,144,0,156,0,0,1,89,0,0,33,61,0,0,0,32,8,64,0,138],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63],[0,0,0,32,10,144,0,57,0,0,7,170,11,0,0,65,0,0,0,0,0,186,4,53,0,0,0,21,10,0,0,57],[0,0,0,0,0,169,4,53,0,0,0,96,8,128,2,16,0,0,0,33,10,144,0,57,0,0,0,0,0,138,4,53],[0,0,0,192,4,64,0,57,0,0,0,0,4,65,3,79,0,0,0,64,8,0,4,61,0,0,0,0,4,4,4,59],[0,9,0,0,0,4,0,29,0,0,0,128,10,64,0,140,0,0,20,168,0,0,65,61,0,0,0,9,4,0,0,41],[0,0,0,128,10,64,2,112,0,0,7,168,11,64,0,156,0,0,0,0,10,4,160,25,0,0,7,168,11,64,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,13,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,7,159,13,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,13,192,1,191,0,0,7,155,10,176,0,156,0,0,0,0,13,12,160,25,0,0,0,32,12,176,2,112],[0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,208,1,191,0,0,255,255,11,192,0,140],[0,0,0,0,10,13,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140],[0,0,0,1,10,160,32,57,0,0,0,32,11,0,0,138,0,0,0,65,12,160,0,57,0,0,0,0,11,188,1,111],[0,0,0,0,11,184,0,25,0,0,0,0,12,139,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57],[0,0,7,159,13,176,0,156,0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,176,4,63,0,0,0,2,11,160,0,57,0,0,0,0,11,184,4,54,0,0,0,33,12,160,0,57],[0,0,0,5,12,192,2,114,0,0,20,32,0,0,97,61,0,0,0,0,13,33,3,79,0,0,0,0,14,0,0,25],[0,0,0,5,15,224,2,16,0,0,0,0,4,251,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59],[0,0,0,0,0,244,4,53,0,0,0,1,14,224,0,57,0,0,0,0,4,206,0,75,0,0,20,24,0,0,65,61],[0,0,0,0,4,0,0,75,0,0,20,34,0,0,97,61,0,0,0,0,4,8,4,51,0,0,0,0,4,4,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,4,11,4,51,0,0,7,167,4,64,1,151,0,0,0,248,12,160,2,16],[0,0,0,0,4,76,1,159,0,0,7,169,4,64,0,65,0,0,0,0,0,75,4,53,0,0,0,3,4,160,2,16],[0,0,0,248,4,64,0,137,0,0,0,9,10,64,1,239,0,0,0,255,4,64,0,140,0,0,0,0,10,0,32,25],[0,0,0,33,4,128,0,57,0,0,0,0,0,164,4,53,0,0,20,187,0,0,1,61,0,0,7,166,4,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,4,128,0,57,0,0,0,64,0,64,4,63,0,0,0,0,4,33,3,79],[0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54,0,0,0,0,4,64,3,80,0,0,0,0,11,4,4,59],[0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61,0,0,0,248,4,144,2,16,0,0,7,160,12,0,0,65],[0,0,0,0,9,9,0,75,0,0,0,0,12,4,192,25,0,0,7,167,4,176,1,151,0,0,0,0,4,196,1,159],[0,0,0,0,0,74,4,53,0,0,0,64,10,0,4,61,0,0,7,166,4,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,9,12,0,0,41,0,0,0,32,4,192,0,138,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59],[0,0,0,64,9,160,0,57,0,0,0,64,0,144,4,63,0,0,0,32,9,160,0,57,0,0,7,170,11,0,0,65],[0,0,0,0,0,185,4,53,0,0,0,21,9,0,0,57,0,0,0,0,0,154,4,53,0,0,0,96,4,64,2,16],[0,0,0,33,9,160,0,57,0,0,0,0,0,73,4,53,0,0,0,192,4,192,0,57,0,0,0,0,4,65,3,79],[0,0,0,64,9,0,4,61,0,0,0,0,4,4,4,59,0,9,0,0,0,4,0,29,0,0,0,128,11,64,0,140],[0,0,21,140,0,0,65,61,0,0,0,9,4,0,0,41,0,0,0,128,11,64,2,112,0,0,7,168,12,64,0,156],[0,0,0,0,11,4,160,25,0,0,7,168,12,64,0,156,0,0,0,0,12,0,0,25,0,0,0,16,12,0,32,57],[0,0,0,8,13,192,1,191,0,0,7,159,14,176,0,156,0,0,0,0,13,12,160,25,0,0,0,64,12,176,2,112],[0,0,7,159,14,176,0,156,0,0,0,0,12,11,160,25,0,0,0,4,14,208,1,191,0,0,7,155,11,192,0,156],[0,0,0,0,14,13,160,25,0,0,0,32,13,192,2,112,0,0,7,155,11,192,0,156,0,0,0,0,13,12,160,25],[0,0,0,2,4,224,1,191,0,0,255,255,12,208,0,140,0,0,0,0,4,14,160,25,0,0,0,16,12,208,2,112],[0,0,0,0,12,13,160,25,0,0,0,255,12,192,0,140,0,0,0,1,4,64,32,57,0,0,0,32,12,0,0,138],[0,8,0,0,0,4,0,29,0,0,0,65,13,64,0,57,0,0,0,0,12,205,1,111,0,0,0,0,12,201,0,25],[0,0,0,0,13,156,0,75,0,0,0,0,13,0,0,25,0,0,0,1,13,0,64,57,0,0,7,159,14,192,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,13,208,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63],[0,0,0,8,4,0,0,41,0,0,0,2,12,64,0,57,0,0,0,0,12,201,4,54,0,0,0,33,13,64,0,57],[0,0,0,5,13,208,2,114,0,0,20,148,0,0,97,61,0,0,0,0,14,33,3,79,0,0,0,0,15,0,0,25],[0,0,0,5,4,240,2,16,0,0,0,0,11,76,0,25,0,0,0,0,4,78,3,79,0,0,0,0,4,4,4,59],[0,0,0,0,0,75,4,53,0,0,0,1,15,240,0,57,0,0,0,0,4,223,0,75,0,0,20,140,0,0,65,61],[0,0,0,0,4,0,0,75,0,0,20,150,0,0,97,61,0,0,0,0,4,9,4,51,0,0,0,0,4,4,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,4,12,4,51,0,0,7,167,4,64,1,151,0,0,0,8,13,0,0,41],[0,0,0,248,11,208,2,16,0,0,0,0,4,75,1,159,0,0,7,169,4,64,0,65,0,0,0,0,0,76,4,53],[0,0,0,3,4,208,2,16,0,0,0,248,4,64,0,137,0,0,0,9,11,64,1,239,0,0,0,255,4,64,0,140],[0,0,0,0,11,0,32,25,0,0,0,33,4,144,0,57,0,0,0,0,0,180,4,53,0,0,21,159,0,0,1,61],[0,0,7,166,4,128,0,156,0,0,1,89,0,0,33,61,0,0,0,64,4,128,0,57,0,0,0,64,0,64,4,63],[0,0,0,0,4,33,3,79,0,0,0,1,10,0,0,58,0,0,0,0,10,168,4,54,0,0,0,0,4,64,3,80],[0,0,0,0,11,4,4,59,0,0,0,0,0,186,4,53,0,0,1,193,0,0,97,61,0,0,0,9,13,0,0,41],[0,0,0,248,4,208,2,16,0,0,7,160,12,0,0,65,0,0,0,0,13,13,0,75,0,0,0,0,12,4,192,25],[0,0,7,167,4,176,1,151,0,0,0,0,4,196,1,159,0,0,0,0,0,74,4,53,0,0,0,64,4,0,4,61],[0,0,0,32,10,64,0,57,0,0,0,0,11,3,4,51,0,0,0,0,12,11,0,75,0,0,20,200,0,0,97,61],[0,0,0,0,12,0,0,25,0,0,0,0,13,172,0,25,0,0,0,32,12,192,0,57,0,0,0,0,14,60,0,25],[0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75,0,0,20,193,0,0,65,61],[0,0,0,0,3,171,0,25,0,0,0,0,0,3,4,53,0,0,0,0,10,5,4,51,0,0,0,0,11,10,0,75],[0,0,20,213,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25,0,0,0,32,11,176,0,57],[0,0,0,0,13,91,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53,0,0,0,0,12,171,0,75],[0,0,20,206,0,0,65,61,0,0,0,0,3,58,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,6,4,51],[0,0,0,0,10,5,0,75,0,0,20,226,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,0,11,58,0,25],[0,0,0,32,10,160,0,57,0,0,0,0,12,106,0,25,0,0,0,0,12,12,4,51,0,0,0,0,0,203,4,53],[0,0,0,0,11,90,0,75,0,0,20,219,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,5,7,4,51,0,0,0,0,6,5,0,75,0,0,20,239,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,10,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,11,118,0,25,0,0,0,0,11,11,4,51],[0,0,0,0,0,186,4,53,0,0,0,0,10,86,0,75,0,0,20,232,0,0,65,61,0,0,0,0,3,53,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,5,9,4,51,0,0,0,0,6,5,0,75,0,0,20,252,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,10,150,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,167,4,53,0,0,0,0,7,86,0,75,0,0,20,245,0,0,65,61],[0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,8,4,51,0,0,0,0,6,5,0,75],[0,0,21,9,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,9,134,0,25,0,0,0,0,9,9,4,51,0,0,0,0,0,151,4,53,0,0,0,0,7,86,0,75],[0,0,21,2,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,3,67,0,73],[0,0,0,32,5,48,0,138,0,0,0,0,0,84,4,53,0,0,0,31,5,48,0,57,0,0,0,32,3,0,0,138],[0,0,0,0,5,53,1,111,0,0,0,0,7,69,0,25,0,0,0,0,5,87,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,7,159,6,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,12,13,0,0,41,0,0,0,0,6,210,0,73],[0,0,0,13,5,0,0,41,0,0,1,196,12,80,0,57,0,0,0,0,5,193,3,79,0,0,0,0,5,5,4,59],[0,0,0,31,9,96,0,138,0,0,7,160,6,144,1,151,0,0,7,160,8,80,1,151,0,0,7,160,10,0,0,65],[0,0,0,0,11,104,0,75,0,0,0,0,11,0,0,25,0,0,0,0,11,10,64,25,0,0,0,0,6,104,1,63],[0,0,0,0,8,149,0,75,0,0,0,0,10,0,64,25,0,0,7,160,6,96,0,156,0,0,0,0,11,10,192,25],[0,0,0,0,6,11,0,75,0,0,0,159,0,0,193,61,0,0,0,0,6,213,0,25,0,0,0,0,5,97,3,79],[0,0,0,0,5,5,4,59,0,0,7,159,8,80,0,156,0,0,0,159,0,0,33,61,0,0,0,0,8,82,0,73],[0,0,0,32,6,96,0,57,0,0,7,160,10,0,0,65,0,0,0,0,11,134,0,75,0,0,0,0,11,0,0,25],[0,0,0,0,11,10,32,25,0,0,7,160,8,128,1,151,0,13,0,0,0,6,0,29,0,0,7,160,13,96,1,151],[0,0,0,0,14,141,0,75,0,0,0,0,10,0,128,25,0,0,0,0,8,141,1,63,0,0,7,160,8,128,0,156],[0,0,0,0,10,11,192,25,0,0,0,0,8,10,0,75,0,0,0,159,0,0,193,61,0,0,0,1,8,80,0,140],[0,0,23,61,0,0,193,61,0,0,0,13,8,16,3,96,0,0,0,0,8,8,4,59,0,0,0,1,10,0,0,138],[0,0,7,160,11,0,0,65,0,0,0,0,10,168,0,75,0,0,0,0,10,0,0,25,0,0,0,0,10,11,32,25],[0,0,7,160,8,128,1,151,0,0,7,160,13,128,0,156,0,0,0,0,11,0,128,25,0,0,7,160,8,128,1,103],[0,0,7,160,8,128,0,156,0,0,0,0,11,10,192,25,0,0,0,96,8,0,0,57,0,0,0,0,10,11,0,75],[0,0,23,158,0,0,193,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57],[0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57,0,0,7,169,10,0,0,65,0,0,0,0,0,168,4,53],[0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53,0,0,0,0,8,7,0,25,0,0,23,158,0,0,1,61],[0,0,0,64,6,0,4,61,0,5,0,0,0,6,0,29,0,0,0,56,6,80,0,140,0,0,22,81,0,0,65,61],[0,0,0,32,7,80,2,112,0,0,7,155,6,80,0,156,0,0,0,0,7,5,160,25,0,0,7,155,6,80,0,156],[0,0,0,0,8,0,0,25,0,0,0,4,8,0,32,57,0,0,0,2,6,128,1,191,0,0,255,255,9,112,0,140],[0,0,0,0,6,8,160,25,0,0,0,16,8,112,2,112,0,0,0,0,8,7,160,25,0,0,0,255,7,128,0,140],[0,0,0,0,7,0,0,25,0,0,0,1,7,0,32,57,0,0,0,5,8,0,0,41,0,0,7,166,8,128,0,156],[0,0,1,89,0,0,33,61,0,0,0,0,6,118,1,159,0,0,0,5,9,0,0,41,0,0,0,64,7,144,0,57],[0,0,0,64,0,112,4,63,0,0,0,0,8,18,3,79,0,0,0,2,7,96,0,58,0,0,0,0,7,121,4,54],[0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59,0,0,0,0,0,135,4,53,0,0,1,193,0,0,97,61],[0,0,7,167,8,128,1,151,0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,171,8,128,1,199],[0,0,0,0,0,135,4,53,0,0,0,3,6,96,2,16,0,0,0,248,6,96,1,95,0,0,0,0,5,101,1,207],[0,0,0,5,6,0,0,41,0,0,0,33,6,96,0,57,0,0,0,0,0,86,4,53,0,0,22,99,0,0,1,61],[0,0,7,166,4,144,0,156,0,0,1,89,0,0,33,61,0,0,0,64,4,144,0,57,0,0,0,64,0,64,4,63],[0,0,0,0,4,33,3,79,0,0,0,1,11,0,0,58,0,0,0,0,11,185,4,54,0,0,0,0,4,64,3,80],[0,0,0,0,12,4,4,59,0,0,0,0,0,203,4,53,0,0,1,193,0,0,97,61,0,0,0,9,14,0,0,41],[0,0,0,248,4,224,2,16,0,0,7,160,13,0,0,65,0,0,0,0,14,14,0,75,0,0,0,0,13,4,192,25],[0,0,7,167,4,192,1,151,0,0,0,0,4,212,1,159,0,0,0,0,0,75,4,53,0,0,0,64,4,0,4,61],[0,0,0,32,11,64,0,57,0,0,0,0,12,3,4,51,0,0,0,0,13,12,0,75,0,0,21,172,0,0,97,61],[0,0,0,0,13,0,0,25,0,0,0,0,14,189,0,25,0,0,0,32,13,208,0,57,0,0,0,0,15,61,0,25],[0,0,0,0,15,15,4,51,0,0,0,0,0,254,4,53,0,0,0,0,14,205,0,75,0,0,21,165,0,0,65,61],[0,0,0,0,3,188,0,25,0,0,0,0,0,3,4,53,0,0,0,0,11,5,4,51,0,0,0,0,12,11,0,75],[0,0,21,185,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,0,13,60,0,25,0,0,0,32,12,192,0,57],[0,0,0,0,14,92,0,25,0,0,0,0,14,14,4,51,0,0,0,0,0,237,4,53,0,0,0,0,13,188,0,75],[0,0,21,178,0,0,65,61,0,0,0,0,3,59,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,6,4,51],[0,0,0,0,11,5,0,75,0,0,21,198,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,12,59,0,25],[0,0,0,32,11,176,0,57,0,0,0,0,13,107,0,25,0,0,0,0,13,13,4,51,0,0,0,0,0,220,4,53],[0,0,0,0,12,91,0,75,0,0,21,191,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,5,7,4,51,0,0,0,0,6,5,0,75,0,0,21,211,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,0,11,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,12,118,0,25,0,0,0,0,12,12,4,51],[0,0,0,0,0,203,4,53,0,0,0,0,11,86,0,75,0,0,21,204,0,0,65,61,0,0,0,0,3,53,0,25],[0,0,0,0,0,3,4,53,0,0,0,0,5,8,4,51,0,0,0,0,6,5,0,75,0,0,21,224,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57,0,0,0,0,11,134,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,183,4,53,0,0,0,0,7,86,0,75,0,0,21,217,0,0,65,61],[0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,10,4,51,0,0,0,0,6,5,0,75],[0,0,21,237,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,8,166,0,25,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,7,86,0,75],[0,0,21,230,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53,0,0,0,0,5,9,4,51],[0,0,0,0,6,5,0,75,0,0,21,250,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,54,0,25],[0,0,0,32,6,96,0,57,0,0,0,0,8,150,0,25,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53],[0,0,0,0,7,86,0,75,0,0,21,243,0,0,65,61,0,0,0,0,3,53,0,25,0,0,0,0,0,3,4,53],[0,0,0,0,3,67,0,73,0,0,0,32,5,48,0,138,0,0,0,0,0,84,4,53,0,0,0,31,5,48,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,5,53,1,111,0,0,0,0,7,69,0,25,0,0,0,0,5,87,0,75],[0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,7,159,6,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,5,80,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63,0,0,0,12,13,0,0,41],[0,0,0,0,6,210,0,73,0,0,0,13,5,0,0,41,0,0,1,196,12,80,0,57,0,0,0,0,5,193,3,79],[0,0,0,0,5,5,4,59,0,0,0,31,9,96,0,138,0,0,7,160,6,144,1,151,0,0,7,160,8,80,1,151],[0,0,7,160,10,0,0,65,0,0,0,0,11,104,0,75,0,0,0,0,11,0,0,25,0,0,0,0,11,10,64,25],[0,0,0,0,6,104,1,63,0,0,0,0,8,149,0,75,0,0,0,0,10,0,64,25,0,0,7,160,6,96,0,156],[0,0,0,0,11,10,192,25,0,0,0,0,6,11,0,75,0,0,0,159,0,0,193,61,0,0,0,0,6,213,0,25],[0,0,0,0,5,97,3,79,0,0,0,0,5,5,4,59,0,0,7,159,8,80,0,156,0,0,0,159,0,0,33,61],[0,0,0,0,8,82,0,73,0,0,0,32,6,96,0,57,0,0,7,160,10,0,0,65,0,0,0,0,11,134,0,75],[0,0,0,0,11,0,0,25,0,0,0,0,11,10,32,25,0,0,7,160,8,128,1,151,0,13,0,0,0,6,0,29],[0,0,7,160,13,96,1,151,0,0,0,0,14,141,0,75,0,0,0,0,10,0,128,25,0,0,0,0,8,141,1,63],[0,0,7,160,8,128,0,156,0,0,0,0,10,11,192,25,0,0,0,0,8,10,0,75,0,0,0,159,0,0,193,61],[0,0,0,1,8,80,0,140,0,0,23,101,0,0,193,61,0,0,0,13,8,16,3,96,0,0,0,0,8,8,4,59],[0,0,0,1,10,0,0,138,0,0,7,160,11,0,0,65,0,0,0,0,10,168,0,75,0,0,0,0,10,0,0,25],[0,0,0,0,10,11,32,25,0,0,7,160,8,128,1,151,0,0,7,160,13,128,0,156,0,0,0,0,11,0,128,25],[0,0,7,160,8,128,1,103,0,0,7,160,8,128,0,156,0,0,0,0,11,10,192,25,0,0,0,96,8,0,0,57],[0,0,0,0,10,11,0,75,0,0,24,125,0,0,193,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63,0,0,0,32,8,112,0,57,0,0,7,169,10,0,0,65],[0,0,0,0,0,168,4,53,0,0,0,1,8,0,0,57,0,0,0,0,0,135,4,53,0,0,0,0,8,7,0,25],[0,0,24,125,0,0,1,61,0,0,0,5,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,5,8,0,0,41,0,0,0,64,6,128,0,57,0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79],[0,0,0,1,6,0,0,58,0,0,0,0,6,104,4,54,0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,1,193,0,0,97,61,0,0,0,248,5,80,2,16,0,0,7,167,7,112,1,151],[0,0,0,0,5,87,1,159,0,0,7,160,5,80,1,103,0,0,0,0,0,86,4,53,0,0,0,32,4,64,0,57],[0,0,0,0,4,66,3,79,0,0,0,0,4,4,4,59,0,0,7,160,5,0,0,65,0,0,0,0,6,52,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,5,128,25,0,0,7,160,3,48,1,151,0,0,7,160,7,64,1,151],[0,0,0,0,8,55,0,75,0,0,0,0,5,0,128,25,0,0,0,0,3,55,1,63,0,0,7,160,3,48,0,156],[0,0,0,0,5,6,192,25,0,0,0,0,3,5,0,75,0,0,0,12,3,0,0,41,0,0,0,159,0,0,193,61],[0,0,0,0,4,52,0,25,0,0,0,0,3,66,3,79,0,0,0,0,3,3,4,59,0,0,7,159,5,48,0,156],[0,0,0,159,0,0,33,61,0,0,0,32,5,48,0,140,0,0,0,159,0,0,65,61,0,0,0,0,5,49,0,73],[0,0,0,32,4,64,0,57,0,0,7,160,6,0,0,65,0,0,0,0,7,84,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,6,32,25,0,0,7,160,5,80,1,151,0,0,7,160,8,64,1,151,0,0,0,0,9,88,0,75],[0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156,0,0,0,0,6,7,192,25],[0,0,0,0,5,6,0,75,0,0,0,159,0,0,193,61,0,0,0,0,5,66,3,79,0,0,0,64,6,0,4,61],[0,4,0,0,0,6,0,29,0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140,0,0,22,216,0,0,65,61],[0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25,0,0,7,168,7,80,0,156],[0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191,0,0,7,159,9,96,0,156],[0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156,0,0,0,0,7,6,160,25],[0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25,0,0,0,32,8,112,2,112],[0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191,0,0,255,255,7,128,0,140],[0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25,0,0,0,255,7,112,0,140],[0,0,0,1,6,96,32,57,0,0,0,65,7,96,0,57,0,0,0,7,7,112,1,127,0,0,0,4,7,112,0,41],[0,0,0,4,8,112,0,108,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57,0,0,7,159,9,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,112,4,63],[0,0,0,2,7,96,0,57,0,0,0,4,8,0,0,41,0,0,0,0,7,120,4,54,0,0,0,33,8,96,0,57],[0,0,0,5,8,128,2,114,0,0,22,196,0,0,97,61,0,0,0,0,9,18,3,79,0,0,0,0,10,0,0,25],[0,0,0,5,11,160,2,16,0,0,0,0,12,183,0,25,0,0,0,0,11,185,3,79,0,0,0,0,11,11,4,59],[0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57,0,0,0,0,11,138,0,75,0,0,22,188,0,0,65,61],[0,0,0,0,8,0,0,75,0,0,22,198,0,0,97,61,0,0,0,4,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,8,8,0,75,0,0,1,193,0,0,97,61,0,0,0,0,8,7,4,51,0,0,7,167,8,128,1,151],[0,0,0,248,9,96,2,16,0,0,0,0,8,137,1,159,0,0,7,169,8,128,0,65,0,0,0,0,0,135,4,53],[0,0,0,3,6,96,2,16,0,0,0,248,6,96,0,137,0,0,0,0,5,101,1,207,0,0,0,255,6,96,0,140],[0,0,0,0,5,0,32,25,0,0,0,4,6,0,0,41,0,0,0,33,6,96,0,57,0,0,22,235,0,0,1,61],[0,0,0,4,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61,0,0,0,4,8,0,0,41],[0,0,0,64,6,128,0,57,0,0,0,64,0,96,4,63,0,0,0,0,7,18,3,79,0,0,0,1,6,0,0,58],[0,0,0,0,6,104,4,54,0,0,0,0,7,112,3,80,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,1,193,0,0,97,61,0,0,0,248,8,80,2,16,0,0,7,160,9,0,0,65,0,0,0,0,5,5,0,75],[0,0,0,0,9,8,192,25,0,0,7,167,5,112,1,151,0,0,0,0,5,149,1,159,0,0,0,0,0,86,4,53],[0,0,0,64,5,48,0,140,0,0,0,159,0,0,65,61,0,0,0,64,5,0,4,61,0,3,0,0,0,5,0,29],[0,0,0,32,4,64,0,57,0,0,0,0,5,66,3,79,0,0,0,0,5,5,4,59,0,0,0,128,6,80,0,140],[0,0,24,41,0,0,65,61,0,0,0,128,6,80,2,112,0,0,7,168,7,80,0,156,0,0,0,0,6,5,160,25],[0,0,7,168,7,80,0,156,0,0,0,0,7,0,0,25,0,0,0,16,7,0,32,57,0,0,0,8,8,112,1,191],[0,0,7,159,9,96,0,156,0,0,0,0,8,7,160,25,0,0,0,64,7,96,2,112,0,0,7,159,9,96,0,156],[0,0,0,0,7,6,160,25,0,0,0,4,9,128,1,191,0,0,7,155,6,112,0,156,0,0,0,0,9,8,160,25],[0,0,0,32,8,112,2,112,0,0,7,155,6,112,0,156,0,0,0,0,8,7,160,25,0,0,0,2,6,144,1,191],[0,0,255,255,7,128,0,140,0,0,0,0,6,9,160,25,0,0,0,16,7,128,2,112,0,0,0,0,7,8,160,25],[0,0,0,255,7,112,0,140,0,0,0,1,6,96,32,57,0,0,0,65,7,96,0,57,0,0,0,7,7,112,1,127],[0,0,0,3,7,112,0,41,0,0,0,3,8,112,0,108,0,0,0,0,8,0,0,25,0,0,0,1,8,0,64,57],[0,0,7,159,9,112,0,156,0,0,1,89,0,0,33,61,0,0,0,1,8,128,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,112,4,63,0,0,0,2,7,96,0,57,0,0,0,3,8,0,0,41,0,0,0,0,7,120,4,54],[0,0,0,33,8,96,0,57,0,0,0,5,8,128,2,114,0,0,23,41,0,0,97,61,0,0,0,0,1,18,3,79],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,167,0,25,0,0,0,0,10,161,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,23,33,0,0,65,61,0,0,0,0,1,0,0,75,0,0,23,43,0,0,97,61,0,0,0,3,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,0,1,1,0,75,0,0,1,193,0,0,97,61,0,0,0,0,1,7,4,51],[0,0,7,167,1,16,1,151,0,0,0,248,8,96,2,16,0,0,0,0,1,24,1,159,0,0,7,169,1,16,0,65],[0,0,0,0,0,23,4,53,0,0,0,3,1,96,2,16,0,0,0,248,1,16,0,137,0,0,0,0,5,21,1,207],[0,0,0,255,1,16,0,140,0,0,0,0,5,0,32,25,0,0,0,3,1,0,0,41,0,0,0,33,1,16,0,57],[0,0,24,60,0,0,1,61,0,0,0,56,8,80,0,140,0,0,23,141,0,0,65,61,0,0,0,32,10,80,2,112],[0,0,7,155,8,80,0,156,0,0,0,0,10,5,160,25,0,0,7,155,8,80,0,156,0,0,0,0,11,0,0,25],[0,0,0,4,11,0,32,57,0,0,0,2,8,176,1,191,0,0,255,255,13,160,0,140,0,0,0,0,8,11,160,25],[0,0,0,16,11,160,2,112,0,0,0,0,11,10,160,25,0,0,0,255,10,176,0,140,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,32,57,0,0,7,166,11,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,8,168,1,159],[0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,11,33,3,79,0,0,0,2,10,128,0,58],[0,0,0,0,10,167,4,54,0,0,0,0,11,176,3,80,0,0,0,0,11,11,4,59,0,0,0,0,0,186,4,53],[0,0,1,193,0,0,97,61,0,0,7,167,11,176,1,151,0,0,0,248,13,128,2,16,0,0,0,0,11,189,1,159],[0,0,7,171,11,176,1,199,0,0,0,0,0,186,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,133,1,207,0,0,0,33,10,112,0,57,0,0,0,0,0,138,4,53,0,0,0,0,8,7,0,25],[0,0,23,158,0,0,1,61,0,0,0,56,8,80,0,140,0,0,24,108,0,0,65,61,0,0,0,32,10,80,2,112],[0,0,7,155,8,80,0,156,0,0,0,0,10,5,160,25,0,0,7,155,8,80,0,156,0,0,0,0,11,0,0,25],[0,0,0,4,11,0,32,57,0,0,0,2,8,176,1,191,0,0,255,255,13,160,0,140,0,0,0,0,8,11,160,25],[0,0,0,16,11,160,2,112,0,0,0,0,11,10,160,25,0,0,0,255,10,176,0,140,0,0,0,0,10,0,0,25],[0,0,0,1,10,0,32,57,0,0,7,166,11,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,8,168,1,159],[0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,11,33,3,79,0,0,0,2,10,128,0,58],[0,0,0,0,10,167,4,54,0,0,0,0,11,176,3,80,0,0,0,0,11,11,4,59,0,0,0,0,0,186,4,53],[0,0,1,193,0,0,97,61,0,0,7,167,11,176,1,151,0,0,0,248,13,128,2,16,0,0,0,0,11,189,1,159],[0,0,7,171,11,176,1,199,0,0,0,0,0,186,4,53,0,0,0,3,8,128,2,16,0,0,0,248,8,128,1,95],[0,0,0,0,8,133,1,207,0,0,0,33,10,112,0,57,0,0,0,0,0,138,4,53,0,0,0,0,8,7,0,25],[0,0,24,125,0,0,1,61,0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57],[0,0,0,64,0,128,4,63,0,0,0,0,10,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,135,4,54],[0,0,0,0,10,160,3,80,0,0,0,0,10,10,4,59,0,0,0,0,0,168,4,53,0,0,1,193,0,0,97,61],[0,0,0,248,11,80,2,16,0,0,7,167,10,160,1,151,0,0,0,0,10,186,1,159,0,0,7,160,10,160,1,103],[0,0,0,0,0,168,4,53,0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61,0,0,7,166,10,112,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,13,33,3,79],[0,0,0,1,6,0,0,58,0,7,0,0,0,6,0,29,0,0,0,0,15,103,4,54,0,0,0,0,6,208,3,80],[0,8,0,0,0,6,3,83,0,0,0,0,6,6,4,59,0,9,0,0,0,6,0,29,0,0,0,0,0,111,4,53],[0,0,1,193,0,0,97,61,0,0,0,9,6,0,0,41,0,0,7,167,6,96,1,151,0,6,0,0,0,6,0,29],[0,0,7,172,11,96,1,199,0,0,0,0,0,191,4,53,0,0,0,32,11,192,0,57,0,0,0,0,11,177,3,79],[0,0,0,0,12,11,4,59,0,0,7,160,11,0,0,65,0,0,0,0,15,156,0,75,0,0,0,0,15,0,0,25],[0,0,0,0,15,11,128,25,0,0,7,160,9,144,1,151,0,0,7,160,14,192,1,151,0,0,0,0,10,158,0,75],[0,0,0,0,11,0,128,25,0,0,0,0,9,158,1,63,0,0,7,160,9,144,0,156,0,0,0,0,11,15,192,25],[0,0,0,0,9,11,0,75,0,0,0,12,6,0,0,41,0,0,0,159,0,0,193,61,0,0,0,0,9,108,0,25],[0,0,0,0,10,145,3,79,0,0,0,0,6,10,4,59,0,12,0,0,0,6,0,29,0,0,7,159,10,96,0,156],[0,0,0,159,0,0,33,61,0,0,0,12,6,0,0,41,0,0,0,32,10,96,0,140,0,0,0,159,0,0,65,61],[0,0,0,12,2,32,0,106,0,0,0,32,6,144,0,57,0,0,7,160,9,0,0,65,0,0,0,0,10,38,0,75],[0,0,0,0,10,0,0,25,0,0,0,0,10,9,32,25,0,0,7,160,2,32,1,151,0,4,0,0,0,6,0,29],[0,0,7,160,11,96,1,151,0,0,0,0,12,43,0,75,0,0,0,0,9,0,128,25,0,0,0,0,2,43,1,63],[0,0,7,160,2,32,0,156,0,0,0,0,9,10,192,25,0,0,0,0,2,9,0,75,0,0,0,159,0,0,193,61],[0,0,0,4,9,16,3,96,0,0,0,64,2,0,4,61,0,0,0,0,6,9,4,59,0,5,0,0,0,6,0,29],[0,0,0,128,10,96,0,140,0,0,0,32,15,32,0,57,0,0,25,8,0,0,65,61,0,0,0,5,6,0,0,41],[0,0,0,128,10,96,2,112,0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,14,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,7,159,14,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,14,192,1,191,0,0,7,155,10,176,0,156,0,0,0,0,14,12,160,25,0,0,0,32,12,176,2,112],[0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,10,224,1,191,0,0,255,255,11,192,0,140],[0,0,0,0,10,14,160,25,0,0,0,16,11,192,2,112,0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140],[0,0,0,1,10,160,32,57,0,0,0,65,11,160,0,57,0,0,0,0,11,59,1,111,0,0,0,0,12,178,0,25],[0,0,0,0,11,44,0,75,0,0,0,0,14,0,0,25,0,0,0,1,14,0,64,57,0,0,7,159,11,192,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,11,224,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63],[0,0,0,2,11,160,0,57,0,0,0,0,0,178,4,53,0,0,0,33,11,160,0,57,0,0,0,5,14,176,2,114],[0,0,24,22,0,0,97,61,0,0,0,0,12,0,0,25,0,0,0,5,11,192,2,16,0,0,0,0,9,191,0,25],[0,0,0,0,11,189,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,185,4,53,0,0,0,1,12,192,0,57],[0,0,0,0,9,236,0,75,0,0,24,14,0,0,65,61,0,0,0,0,6,0,0,75,0,0,24,24,0,0,97,61],[0,0,0,0,9,2,4,51,0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,15,4,51],[0,0,7,167,9,144,1,151,0,0,0,248,11,160,2,16,0,0,0,0,9,155,1,159,0,0,7,169,9,144,0,65],[0,0,0,0,0,159,4,53,0,0,0,3,9,160,2,16,0,0,0,248,9,144,0,137,0,0,0,5,10,144,1,239],[0,0,0,255,9,144,0,140,0,0,0,0,10,0,32,25,0,0,0,33,9,32,0,57,0,0,0,0,0,169,4,53],[0,0,25,25,0,0,1,61,0,0,0,3,6,0,0,41,0,0,7,166,6,96,0,156,0,0,1,89,0,0,33,61],[0,0,0,3,7,0,0,41,0,0,0,64,6,112,0,57,0,0,0,64,0,96,4,63,0,0,0,0,6,18,3,79],[0,0,0,1,1,0,0,58,0,0,0,0,1,23,4,54,0,0,0,0,6,96,3,80,0,0,0,0,6,6,4,59],[0,0,0,0,0,97,4,53,0,0,1,193,0,0,97,61,0,0,0,248,7,80,2,16,0,0,7,160,8,0,0,65],[0,0,0,0,5,5,0,75,0,0,0,0,8,7,192,25,0,0,7,167,5,96,1,151,0,0,0,0,5,133,1,159],[0,0,0,0,0,81,4,53,0,0,0,65,1,48,0,140,0,0,1,193,0,0,65,61,0,0,0,32,1,64,0,57],[0,0,0,0,1,18,3,79,0,0,0,0,1,1,4,59,0,0,0,248,1,16,2,112,0,2,0,0,0,1,0,29],[0,0,0,27,1,16,0,138,0,0,0,2,1,16,0,140,0,0,29,6,0,0,129,61,0,0,0,13,1,0,0,41],[0,1,1,68,0,16,0,61,0,0,0,1,1,32,3,96,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,26,146,0,0,97,61,0,0,7,164,1,0,0,65,0,0,0,0,0,16,4,57,0,0,7,155,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,7,155,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,7,165,1,16,1,199,0,0,128,11,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,24,107,0,0,97,61,0,0,0,0,2,1,4,59,0,0,0,1,1,32,2,16,0,0,0,0,3,2,0,75],[0,0,24,99,0,0,97,61,0,0,0,9,3,0,0,138,0,0,0,0,3,49,0,75,0,0,24,103,0,0,33,61],[0,0,0,0,50,33,0,217,0,0,0,2,2,32,0,140,0,0,24,103,0,0,193,61,0,0,0,2,1,16,0,41],[0,0,0,8,3,16,0,57,0,0,0,2,1,48,0,108,0,0,25,110,0,0,129,61,0,0,7,195,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,1,196,0,0,1,61,0,0,0,0,0,1,4,47],[0,0,7,166,8,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,8,112,0,57,0,0,0,64,0,128,4,63],[0,0,0,0,10,33,3,79,0,0,0,1,8,0,0,58,0,0,0,0,8,135,4,54,0,0,0,0,10,160,3,80],[0,0,0,0,10,10,4,59,0,0,0,0,0,168,4,53,0,0,1,193,0,0,97,61,0,0,0,248,11,80,2,16],[0,0,7,167,10,160,1,151,0,0,0,0,10,186,1,159,0,0,7,160,10,160,1,103,0,0,0,0,0,168,4,53],[0,0,0,0,8,7,0,25,0,0,0,64,7,0,4,61,0,0,7,166,10,112,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,10,112,0,57,0,0,0,64,0,160,4,63,0,0,0,0,13,33,3,79,0,0,0,1,6,0,0,58],[0,9,0,0,0,6,0,29,0,0,0,0,10,103,4,54,0,0,0,0,6,208,3,80,0,7,0,0,0,6,3,83],[0,0,0,0,6,6,4,59,0,8,0,0,0,6,0,29,0,0,0,0,0,106,4,53,0,0,1,193,0,0,97,61],[0,0,0,8,6,0,0,41,0,0,7,167,6,96,1,151,0,5,0,0,0,6,0,29,0,0,7,172,15,96,1,199],[0,0,0,0,0,250,4,53,0,0,0,32,10,192,0,57,0,0,0,0,10,161,3,79,0,0,0,0,10,10,4,59],[0,0,7,160,12,0,0,65,0,0,0,0,15,154,0,75,0,0,0,0,15,0,0,25,0,0,0,0,15,12,128,25],[0,0,7,160,9,144,1,151,0,0,7,160,14,160,1,151,0,0,0,0,11,158,0,75,0,0,0,0,12,0,128,25],[0,0,0,0,9,158,1,63,0,0,7,160,9,144,0,156,0,0,0,0,12,15,192,25,0,0,0,0,9,12,0,75],[0,0,0,12,6,0,0,41,0,0,0,159,0,0,193,61,0,0,0,0,9,106,0,25,0,0,0,0,10,145,3,79],[0,0,0,0,6,10,4,59,0,12,0,0,0,6,0,29,0,0,7,159,10,96,0,156,0,0,0,159,0,0,33,61],[0,0,0,12,6,0,0,41,0,0,0,32,10,96,0,140,0,0,0,159,0,0,65,61,0,0,0,12,2,32,0,106],[0,0,0,32,6,144,0,57,0,0,7,160,9,0,0,65,0,0,0,0,10,38,0,75,0,0,0,0,10,0,0,25],[0,0,0,0,10,9,32,25,0,0,7,160,2,32,1,151,0,4,0,0,0,6,0,29,0,0,7,160,11,96,1,151],[0,0,0,0,14,43,0,75,0,0,0,0,9,0,128,25,0,0,0,0,2,43,1,63,0,0,7,160,2,32,0,156],[0,0,0,0,9,10,192,25,0,0,0,0,2,9,0,75,0,0,0,159,0,0,193,61,0,0,0,4,9,16,3,96],[0,0,0,64,2,0,4,61,0,0,0,0,6,9,4,59,0,6,0,0,0,6,0,29,0,0,0,128,10,96,0,140],[0,0,0,32,15,32,0,57,0,0,25,186,0,0,65,61,0,0,0,6,6,0,0,41,0,0,0,128,10,96,2,112],[0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156,0,0,0,0,11,0,0,25],[0,0,0,16,11,0,32,57,0,0,0,8,14,176,1,191,0,0,7,159,12,160,0,156,0,0,0,0,14,11,160,25],[0,0,0,64,11,160,2,112,0,0,7,159,12,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,10,224,1,191],[0,0,7,155,12,176,0,156,0,0,0,0,10,14,160,25,0,0,0,32,12,176,2,112,0,0,7,155,14,176,0,156],[0,0,0,0,12,11,160,25,0,0,0,2,11,160,1,191,0,0,255,255,14,192,0,140,0,0,0,0,11,10,160,25],[0,0,0,16,10,192,2,112,0,0,0,0,10,12,160,25,0,0,0,255,10,160,0,140,0,0,0,1,11,176,32,57],[0,0,0,65,10,176,0,57,0,0,0,0,10,58,1,111,0,0,0,0,10,162,0,25,0,0,0,0,12,42,0,75],[0,0,0,0,14,0,0,25,0,0,0,1,14,0,64,57,0,0,7,159,12,160,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,12,224,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,160,4,63,0,0,0,2,10,176,0,57],[0,0,0,0,0,162,4,53,0,0,0,33,10,176,0,57,0,0,0,5,10,160,2,114,0,0,24,245,0,0,97,61],[0,0,0,0,14,0,0,25,0,0,0,5,12,224,2,16,0,0,0,0,9,207,0,25,0,0,0,0,12,205,3,79],[0,0,0,0,12,12,4,59,0,0,0,0,0,201,4,53,0,0,0,1,14,224,0,57,0,0,0,0,9,174,0,75],[0,0,24,237,0,0,65,61,0,0,0,0,6,0,0,75,0,0,24,247,0,0,97,61,0,0,0,0,9,2,4,51],[0,0,0,0,9,9,0,75,0,0,1,193,0,0,97,61,0,0,0,0,9,15,4,51,0,0,7,167,9,144,1,151],[0,0,0,248,10,176,2,16,0,0,0,0,9,154,1,159,0,0,7,169,9,144,0,65,0,0,0,0,0,159,4,53],[0,0,0,3,9,176,2,16,0,0,0,248,9,144,0,137,0,0,0,6,10,144,1,239,0,0,0,255,9,144,0,140],[0,0,0,0,10,0,32,25,0,0,0,33,9,32,0,57,0,0,0,0,0,169,4,53,0,0,25,203,0,0,1,61],[0,0,7,166,9,32,0,156,0,0,1,89,0,0,33,61,0,0,0,64,9,32,0,57,0,0,0,64,0,144,4,63],[0,0,0,9,6,0,0,41,0,0,0,0,0,111,4,53,0,0,0,7,6,0,0,41,0,0,0,0,0,98,4,53],[0,0,0,0,9,6,0,75,0,0,1,193,0,0,97,61,0,0,0,5,6,0,0,41,0,0,0,248,9,96,2,16],[0,0,7,160,10,0,0,65,0,0,0,0,11,6,0,75,0,0,0,0,10,9,192,25,0,0,0,6,9,160,1,175],[0,0,0,0,0,159,4,53,0,0,0,12,6,0,0,41,0,0,0,64,9,96,0,140,0,0,0,159,0,0,65,61],[0,0,0,64,9,0,4,61,0,0,0,4,6,0,0,41,0,5,0,32,0,96,0,61,0,0,0,5,10,16,3,96],[0,0,0,0,6,10,4,59,0,9,0,0,0,6,0,29,0,0,0,128,10,96,0,140,0,0,0,32,14,144,0,57],[0,0,26,32,0,0,65,61,0,0,0,9,6,0,0,41,0,0,0,128,10,96,2,112,0,0,7,168,11,96,0,156],[0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156,0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57],[0,0,0,8,12,176,1,191,0,0,7,159,15,160,0,156,0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112],[0,0,7,159,15,160,0,156,0,0,0,0,11,10,160,25,0,0,0,4,15,192,1,191,0,0,7,155,10,176,0,156],[0,0,0,0,15,12,160,25,0,0,0,32,12,176,2,112,0,0,7,155,10,176,0,156,0,0,0,0,12,11,160,25],[0,0,0,2,6,240,1,191,0,0,255,255,11,192,0,140,0,0,0,0,6,15,160,25,0,0,0,16,11,192,2,112],[0,0,0,0,11,12,160,25,0,0,0,255,11,176,0,140,0,0,0,1,6,96,32,57,0,6,0,0,0,6,0,29],[0,0,0,65,11,96,0,57,0,0,0,0,11,59,1,111,0,0,0,0,12,185,0,25,0,0,0,0,11,156,0,75],[0,0,0,0,15,0,0,25,0,0,0,1,15,0,64,57,0,0,7,159,11,192,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,11,240,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,192,4,63,0,0,0,6,6,0,0,41],[0,0,0,2,11,96,0,57,0,0,0,0,0,185,4,53,0,0,0,33,11,96,0,57,0,0,0,5,12,176,2,114],[0,0,25,90,0,0,97,61,0,0,0,0,15,0,0,25,0,0,0,5,11,240,2,16,0,0,0,0,10,190,0,25],[0,0,0,0,11,189,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,186,4,53,0,0,0,1,15,240,0,57],[0,0,0,0,10,207,0,75,0,0,25,82,0,0,65,61,0,0,0,0,6,0,0,75,0,0,25,92,0,0,97,61],[0,0,0,0,10,9,4,51,0,0,0,0,10,10,0,75,0,0,1,193,0,0,97,61,0,0,0,0,10,14,4,51],[0,0,7,167,10,160,1,151,0,0,0,6,6,0,0,41,0,0,0,248,11,96,2,16,0,0,0,0,10,171,1,159],[0,0,7,169,10,160,0,65,0,0,0,0,0,174,4,53,0,0,0,3,10,96,2,16,0,0,0,248,10,160,0,137],[0,0,0,9,11,160,1,239,0,0,0,255,10,160,0,140,0,0,0,0,11,0,32,25,0,0,0,33,10,144,0,57],[0,0,0,0,0,186,4,53,0,0,26,51,0,0,1,61,0,0,0,128,1,48,0,140,0,2,0,0,0,3,0,29],[0,0,26,146,0,0,65,61,0,0,0,128,1,48,2,112,0,0,7,168,2,48,0,156,0,0,0,0,1,3,160,25],[0,0,7,168,2,48,0,156,0,0,0,0,2,0,0,25,0,0,0,16,2,0,32,57,0,0,0,8,4,32,1,191],[0,0,7,159,5,16,0,156,0,0,0,0,4,2,160,25,0,0,0,64,2,16,2,112,0,0,7,159,5,16,0,156],[0,0,0,0,2,1,160,25,0,0,0,4,1,64,1,191,0,0,7,155,5,32,0,156,0,0,0,0,1,4,160,25],[0,0,0,32,4,32,2,112,0,0,7,155,5,32,0,156,0,0,0,0,4,2,160,25,0,0,0,2,5,16,1,191],[0,0,255,255,2,64,0,140,0,0,0,0,5,1,160,25,0,0,0,16,1,64,2,112,0,0,0,0,1,4,160,25],[0,0,0,255,1,16,0,140,0,0,0,1,5,80,32,57,0,0,0,65,1,80,0,57,0,0,0,7,2,16,1,127],[0,0,0,64,1,0,4,61,0,0,0,0,2,33,0,25,0,0,0,0,4,18,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,64,57,0,0,7,159,6,32,0,156,0,0,1,89,0,0,33,61,0,0,0,1,4,64,1,144],[0,0,1,89,0,0,193,61,0,0,0,64,0,32,4,63,0,0,0,2,2,80,0,57,0,0,0,0,6,33,4,54],[0,0,0,1,2,0,3,103,0,0,0,0,4,0,0,49,0,0,0,33,7,80,0,57,0,0,0,5,7,112,2,114],[0,0,25,167,0,0,97,61,0,0,0,0,8,66,3,79,0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16],[0,0,0,0,11,166,0,25,0,0,0,0,10,168,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,9,144,0,57,0,0,0,0,10,121,0,75,0,0,25,159,0,0,65,61,0,0,0,0,7,0,0,75],[0,0,25,169,0,0,97,61,0,0,0,0,7,1,4,51,0,0,0,0,7,7,0,75,0,0,1,193,0,0,97,61],[0,0,0,0,7,6,4,51,0,0,7,167,7,112,1,151,0,0,0,248,8,80,2,16,0,0,0,0,7,120,1,159],[0,0,7,169,7,112,0,65,0,0,0,0,0,118,4,53,0,0,0,3,5,80,2,16,0,0,0,248,5,80,0,137],[0,0,0,0,3,83,1,207,0,0,0,255,5,80,0,140,0,0,0,0,3,0,32,25,0,0,0,33,5,16,0,57],[0,0,0,0,0,53,4,53,0,0,26,168,0,0,1,61,0,0,7,166,9,32,0,156,0,0,1,89,0,0,33,61],[0,0,0,64,9,32,0,57,0,0,0,64,0,144,4,63,0,0,0,8,6,0,0,41,0,0,0,0,0,111,4,53],[0,0,0,9,6,0,0,41,0,0,0,0,0,98,4,53,0,0,0,0,9,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,6,6,0,0,41,0,0,0,248,9,96,2,16,0,0,7,160,10,0,0,65,0,0,0,0,11,6,0,75],[0,0,0,0,10,9,192,25,0,0,0,5,9,160,1,175,0,0,0,0,0,159,4,53,0,0,0,12,6,0,0,41],[0,0,0,64,9,96,0,140,0,0,0,159,0,0,65,61,0,0,0,64,9,0,4,61,0,0,0,4,6,0,0,41],[0,5,0,32,0,96,0,61,0,0,0,5,10,16,3,96,0,0,0,0,6,10,4,59,0,8,0,0,0,6,0,29],[0,0,0,128,10,96,0,140,0,0,0,32,14,144,0,57,0,0,27,17,0,0,65,61,0,0,0,8,6,0,0,41],[0,0,0,128,10,96,2,112,0,0,7,168,11,96,0,156,0,0,0,0,10,6,160,25,0,0,7,168,11,96,0,156],[0,0,0,0,11,0,0,25,0,0,0,16,11,0,32,57,0,0,0,8,12,176,1,191,0,0,7,159,15,160,0,156],[0,0,0,0,12,11,160,25,0,0,0,64,11,160,2,112,0,0,7,159,15,160,0,156,0,0,0,0,11,10,160,25],[0,0,0,4,10,192,1,191,0,0,7,155,15,176,0,156,0,0,0,0,10,12,160,25,0,0,0,32,12,176,2,112],[0,0,7,155,15,176,0,156,0,0,0,0,12,11,160,25,0,0,0,2,6,160,1,191,0,0,255,255,15,192,0,140],[0,0,0,0,6,10,160,25,0,0,0,16,10,192,2,112,0,0,0,0,10,12,160,25,0,0,0,255,10,160,0,140],[0,0,0,1,6,96,32,57,0,6,0,0,0,6,0,29,0,0,0,65,10,96,0,57,0,0,0,0,10,58,1,111],[0,0,0,0,10,169,0,25,0,0,0,0,12,154,0,75,0,0,0,0,12,0,0,25,0,0,0,1,12,0,64,57],[0,0,7,159,15,160,0,156,0,0,1,89,0,0,33,61,0,0,0,1,12,192,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,160,4,63,0,0,0,6,6,0,0,41,0,0,0,2,10,96,0,57,0,0,0,0,0,169,4,53],[0,0,0,33,10,96,0,57,0,0,0,5,10,160,2,114,0,0,26,12,0,0,97,61,0,0,0,0,12,0,0,25],[0,0,0,5,15,192,2,16,0,0,0,0,11,254,0,25,0,0,0,0,15,253,3,79,0,0,0,0,15,15,4,59],[0,0,0,0,0,251,4,53,0,0,0,1,12,192,0,57,0,0,0,0,11,172,0,75,0,0,26,4,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,26,14,0,0,97,61,0,0,0,0,10,9,4,51,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,0,0,10,14,4,51,0,0,7,167,10,160,1,151,0,0,0,6,6,0,0,41],[0,0,0,248,11,96,2,16,0,0,0,0,10,171,1,159,0,0,7,169,10,160,0,65,0,0,0,0,0,174,4,53],[0,0,0,3,10,96,2,16,0,0,0,248,10,160,0,137,0,0,0,8,11,160,1,239,0,0,0,255,10,160,0,140],[0,0,0,0,11,0,32,25,0,0,0,33,10,144,0,57,0,0,0,0,0,186,4,53,0,0,27,36,0,0,1,61],[0,0,7,166,10,144,0,156,0,0,1,89,0,0,33,61,0,0,0,64,10,144,0,57,0,0,0,64,0,160,4,63],[0,0,0,7,11,0,0,41,0,0,0,0,0,185,4,53,0,0,0,8,6,0,3,95,0,0,0,0,10,6,4,59],[0,0,0,0,0,174,4,53,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,0,9,6,0,0,41],[0,0,0,248,11,96,2,16,0,0,7,160,12,0,0,65,0,0,0,0,13,6,0,75,0,0,0,0,12,11,192,25],[0,0,7,167,10,160,1,151,0,0,0,0,10,202,1,159,0,0,0,0,0,174,4,53,0,0,0,12,6,0,0,41],[0,0,0,65,10,96,0,140,0,0,1,193,0,0,65,61,0,0,0,5,6,0,0,41,0,0,0,32,10,96,0,57],[0,0,0,0,11,161,3,79,0,0,0,0,10,0,4,21,0,0,0,17,10,160,0,138,0,0,0,32,10,160,0,201],[0,0,7,160,13,0,0,65,0,0,0,0,11,11,4,59,0,0,0,248,12,176,2,112,0,0,0,27,11,192,0,140],[0,0,26,71,0,0,97,61,0,0,0,0,10,0,4,21,0,0,0,16,10,160,0,138,0,0,0,32,10,160,0,201],[0,0,7,174,13,0,0,65,0,0,0,28,11,192,0,140,0,0,29,6,0,0,193,61,0,0,0,64,12,0,4,61],[0,0,7,166,11,192,0,156,0,0,1,89,0,0,33,61,0,0,0,64,11,192,0,57,0,0,0,64,0,176,4,63],[0,0,0,7,11,0,0,41,0,0,0,0,14,188,4,54,0,0,0,8,6,0,3,95,0,0,0,0,15,6,4,59],[0,0,0,0,0,254,4,53,0,0,0,0,11,11,0,75,0,0,1,193,0,0,97,61,0,0,7,167,11,240,1,151],[0,0,0,0,11,219,1,159,0,0,0,0,0,190,4,53,0,0,0,0,11,4,4,51,0,0,0,0,13,8,4,51],[0,0,0,5,10,160,2,112,0,0,0,0,10,12,0,31,0,0,0,0,10,93,0,25,0,0,0,0,10,186,0,25],[0,0,0,0,11,7,4,51,0,0,0,0,10,186,0,25,0,0,0,0,11,2,4,51,0,0,0,0,10,186,0,25],[0,0,0,0,11,9,4,51,0,0,0,0,10,186,0,25,0,0,0,0,11,12,4,51,0,0,0,0,10,186,0,25],[0,0,0,64,13,0,4,61,0,0,7,159,6,160,1,151,0,9,0,0,0,6,0,29,0,0,0,56,11,96,0,140],[0,6,0,64,0,208,0,61,0,12,0,32,0,208,0,61,0,0,27,129,0,0,65,61,0,0,0,9,6,0,0,41],[0,0,0,32,15,96,2,112,0,0,7,155,11,96,0,156,0,0,0,0,15,6,160,25,0,0,7,155,11,96,0,156],[0,0,0,0,14,0,0,25,0,0,0,4,14,0,32,57,0,0,0,2,11,224,1,191,0,0,255,255,10,240,0,140],[0,0,0,0,11,14,160,25,0,0,0,16,10,240,2,112,0,0,0,0,10,15,160,25,0,0,0,255,10,160,0,140],[0,0,0,0,15,0,0,25,0,0,0,1,15,0,32,57,0,0,7,166,10,208,0,156,0,0,1,89,0,0,33,61],[0,0,0,0,11,251,1,159,0,0,0,6,6,0,0,41,0,0,0,64,0,96,4,63,0,0,0,2,10,176,0,58],[0,0,0,0,0,173,4,53,0,0,0,8,6,0,3,95,0,0,0,0,15,6,4,59,0,0,0,12,6,0,0,41],[0,0,0,0,0,246,4,53,0,0,1,193,0,0,97,61,0,0,7,167,10,240,1,151,0,0,0,248,14,176,2,16],[0,0,0,0,10,174,1,159,0,0,7,173,10,160,1,199,0,0,0,12,6,0,0,41,0,0,0,0,0,166,4,53],[0,0,0,3,10,176,2,16,0,0,0,248,10,160,1,95,0,0,0,9,10,160,1,239,0,0,0,33,11,208,0,57],[0,0,0,0,0,171,4,53,0,0,27,148,0,0,1,61,0,0,0,64,1,0,4,61,0,0,7,166,2,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,64,2,16,0,57,0,0,0,64,0,32,4,63,0,0,0,1,2,0,0,58],[0,0,0,0,3,33,4,54,0,0,0,0,4,0,0,49,0,0,0,1,2,0,3,103,0,0,0,0,5,66,3,79],[0,0,0,0,5,80,3,80,0,0,0,0,5,5,4,59,0,0,0,0,0,83,4,53,0,0,1,193,0,0,97,61],[0,0,0,2,8,0,0,41,0,0,0,248,6,128,2,16,0,0,7,160,7,0,0,65,0,0,0,0,8,8,0,75],[0,0,0,0,7,6,192,25,0,0,7,167,5,80,1,151,0,0,0,0,5,117,1,159,0,0,0,0,0,83,4,53],[0,0,0,1,3,0,0,41,0,0,0,128,3,48,0,57,0,0,0,0,3,50,3,79,0,0,0,13,5,64,0,106],[0,0,0,35,5,80,0,138,0,0,0,0,3,3,4,59,0,0,7,160,6,0,0,65,0,0,0,0,7,83,0,75],[0,0,0,0,7,0,0,25,0,0,0,0,7,6,128,25,0,0,7,160,5,80,1,151,0,0,7,160,8,48,1,151],[0,0,0,0,9,88,0,75,0,0,0,0,6,0,128,25,0,0,0,0,5,88,1,63,0,0,7,160,5,80,0,156],[0,0,0,0,6,7,192,25,0,0,0,0,5,6,0,75,0,0,0,12,6,0,0,41,0,0,0,159,0,0,193,61],[0,0,0,10,5,0,0,41,0,0,0,0,5,5,4,51,0,0,0,9,7,0,0,41,0,0,0,0,7,7,4,51],[0,0,0,8,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,6,9,0,0,41,0,0,0,0,9,9,4,51],[0,0,0,5,10,0,0,41,0,0,0,0,10,10,4,51,0,0,0,0,6,99,0,25,0,0,0,0,3,98,3,79],[0,0,0,0,3,3,4,59,0,0,7,159,11,48,0,156,0,0,0,159,0,0,33,61,0,0,0,0,11,52,0,73],[0,0,0,32,6,96,0,57,0,0,7,160,12,0,0,65,0,0,0,0,13,182,0,75,0,0,0,0,13,0,0,25],[0,0,0,0,13,12,32,25,0,0,7,160,11,176,1,151,0,0,7,160,14,96,1,151,0,0,0,0,15,190,0,75],[0,0,0,0,12,0,128,25,0,0,0,0,11,190,1,63,0,0,7,160,11,176,0,156,0,0,0,0,12,13,192,25],[0,0,0,0,11,12,0,75,0,0,0,159,0,0,193,61,0,0,0,0,5,87,0,25,0,0,0,0,5,133,0,25],[0,0,0,0,5,149,0,25,0,0,0,0,5,165,0,25,0,0,0,0,5,53,0,25,0,0,0,4,7,0,0,41],[0,0,0,0,7,7,4,51,0,0,0,0,5,117,0,25,0,0,0,3,7,0,0,41,0,0,0,0,7,7,4,51],[0,0,0,0,5,117,0,25,0,0,0,0,7,1,4,51,0,0,0,0,5,117,0,25,0,0,0,64,7,0,4,61],[0,0,7,159,5,80,1,151,0,0,0,56,8,80,0,140,0,0,0,64,9,112,0,57,0,0,0,0,8,66,3,79],[0,0,0,32,4,112,0,57,0,0,28,57,0,0,65,61,0,0,0,32,11,80,2,112,0,0,7,155,10,80,0,156],[0,0,0,0,11,5,160,25,0,0,7,155,10,80,0,156,0,0,0,0,12,0,0,25,0,0,0,4,12,0,32,57],[0,0,0,2,10,192,1,191,0,0,255,255,13,176,0,140,0,0,0,0,10,12,160,25,0,0,0,16,12,176,2,112],[0,0,0,0,12,11,160,25,0,0,0,255,11,192,0,140,0,0,0,0,11,0,0,25,0,0,0,1,11,0,32,57],[0,0,7,166,12,112,0,156,0,0,1,89,0,0,33,61,0,0,0,0,10,186,1,159,0,0,0,64,0,144,4,63],[0,0,0,2,9,160,0,58,0,0,0,0,0,151,4,53,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,132,4,53,0,0,1,193,0,0,97,61,0,0,7,167,8,128,1,151,0,0,0,248,9,160,2,16],[0,0,0,0,8,137,1,159,0,0,7,173,8,128,1,199,0,0,0,0,0,132,4,53,0,0,0,3,4,160,2,16],[0,0,0,248,4,64,1,95,0,0,0,0,4,69,1,207,0,0,0,33,5,112,0,57,0,0,0,0,0,69,4,53],[0,0,28,71,0,0,1,61,0,0,7,166,10,144,0,156,0,0,1,89,0,0,33,61,0,0,0,64,10,144,0,57],[0,0,0,64,0,160,4,63,0,0,0,9,6,0,0,41,0,0,0,0,0,105,4,53,0,0,0,7,10,0,3,95],[0,0,0,0,10,10,4,59,0,0,0,0,0,174,4,53,0,0,0,0,11,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,8,6,0,0,41,0,0,0,248,11,96,2,16,0,0,7,160,12,0,0,65,0,0,0,0,13,6,0,75],[0,0,0,0,12,11,192,25,0,0,7,167,10,160,1,151,0,0,0,0,10,202,1,159,0,0,0,0,0,174,4,53],[0,0,0,12,6,0,0,41,0,0,0,65,10,96,0,140,0,0,1,193,0,0,65,61,0,0,0,5,6,0,0,41],[0,0,0,32,10,96,0,57,0,0,0,0,10,161,3,79,0,0,0,0,11,0,4,21,0,0,0,15,11,176,0,138],[0,0,0,32,11,176,0,201,0,0,7,160,13,0,0,65,0,0,0,0,10,10,4,59,0,0,0,248,10,160,2,112],[0,0,0,27,12,160,0,140,0,0,27,56,0,0,97,61,0,0,0,0,11,0,4,21,0,0,0,14,11,176,0,138],[0,0,0,32,11,176,0,201,0,0,7,174,13,0,0,65,0,0,0,28,10,160,0,140,0,0,29,6,0,0,193,61],[0,0,0,64,12,0,4,61,0,0,7,166,10,192,0,156,0,0,1,89,0,0,33,61,0,0,0,64,10,192,0,57],[0,0,0,64,0,160,4,63,0,0,0,9,6,0,0,41,0,0,0,0,10,108,4,54,0,0,0,7,14,0,3,95],[0,0,0,0,14,14,4,59,0,8,0,0,0,14,0,29,0,0,0,0,0,234,4,53,0,0,0,0,14,6,0,75],[0,0,1,193,0,0,97,61,0,0,0,8,6,0,0,41,0,7,7,167,0,96,1,155,0,0,0,7,13,208,1,175],[0,0,0,0,0,218,4,53,0,0,0,0,10,4,4,51,0,0,0,0,13,8,4,51,0,0,0,5,11,176,2,112],[0,0,0,0,11,12,0,31,0,0,0,0,11,93,0,25,0,0,0,0,10,171,0,25,0,0,0,0,11,7,4,51],[0,0,0,0,10,186,0,25,0,0,0,0,11,2,4,51,0,0,0,0,10,186,0,25,0,0,0,0,11,9,4,51],[0,0,0,0,10,186,0,25,0,0,0,0,11,12,4,51,0,0,0,0,10,186,0,25,0,0,0,64,13,0,4,61],[0,0,7,159,15,160,1,151,0,0,0,56,10,240,0,140,0,6,0,64,0,208,0,61,0,12,0,32,0,208,0,61],[0,0,29,13,0,0,65,61,0,0,0,32,14,240,2,112,0,0,7,155,10,240,0,156,0,0,0,0,14,15,160,25],[0,0,7,155,10,240,0,156,0,0,0,0,6,0,0,25,0,0,0,4,6,0,32,57,0,0,0,2,10,96,1,191],[0,0,255,255,11,224,0,140,0,0,0,0,10,6,160,25,0,0,0,16,11,224,2,112,0,0,0,0,11,14,160,25],[0,0,0,255,11,176,0,140,0,0,0,0,14,0,0,25,0,0,0,1,14,0,32,57,0,0,7,166,11,208,0,156],[0,0,1,89,0,0,33,61,0,0,0,0,10,234,1,159,0,0,0,6,6,0,0,41,0,0,0,64,0,96,4,63],[0,0,0,8,6,0,0,41,0,0,0,12,11,0,0,41,0,0,0,0,0,107,4,53,0,0,0,2,11,160,0,58],[0,0,0,0,0,189,4,53,0,0,1,193,0,0,97,61,0,0,0,248,11,160,2,16,0,0,0,7,11,176,1,175],[0,0,7,173,11,176,1,199,0,0,0,12,6,0,0,41,0,0,0,0,0,182,4,53,0,0,0,3,10,160,2,16],[0,0,0,248,10,160,1,95,0,0,0,0,10,175,1,207,0,0,0,33,11,208,0,57,0,0,0,0,0,171,4,53],[0,0,29,29,0,0,1,61,0,0,7,166,10,208,0,156,0,0,1,89,0,0,33,61,0,0,0,6,6,0,0,41],[0,0,0,64,0,96,4,63,0,0,0,7,10,0,0,41,0,0,0,0,0,173,4,53,0,0,0,8,6,0,3,95],[0,0,0,0,15,6,4,59,0,0,0,12,6,0,0,41,0,0,0,0,0,246,4,53,0,0,0,0,10,10,0,75],[0,0,1,193,0,0,97,61,0,0,7,167,10,240,1,151,0,0,0,9,6,0,0,41,0,0,0,248,11,96,2,16],[0,0,0,0,10,171,1,159,0,0,7,172,10,160,0,65,0,0,0,12,6,0,0,41,0,0,0,0,0,166,4,53],[0,0,0,64,6,0,4,61,0,0,0,32,10,96,0,57,0,0,7,174,11,0,0,65,0,9,0,0,0,10,0,29],[0,0,0,0,0,186,4,53,0,12,0,0,0,6,0,29,0,0,0,33,14,96,0,57,0,0,0,0,15,13,4,51],[0,0,0,0,11,15,0,75,0,0,27,166,0,0,97,61,0,0,0,0,11,0,0,25,0,0,0,0,10,235,0,25],[0,0,0,32,11,176,0,57,0,0,0,0,6,219,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,106,4,53],[0,0,0,0,6,251,0,75,0,0,27,159,0,0,65,61,0,0,0,0,13,239,0,25,0,0,0,0,0,13,4,53],[0,0,0,0,14,4,4,51,0,0,0,0,6,14,0,75,0,0,27,179,0,0,97,61,0,0,0,0,11,0,0,25],[0,0,0,0,6,219,0,25,0,0,0,32,11,176,0,57,0,0,0,0,10,75,0,25,0,0,0,0,10,10,4,51],[0,0,0,0,0,166,4,53,0,0,0,0,6,235,0,75,0,0,27,172,0,0,65,61,0,0,0,0,13,222,0,25],[0,0,0,0,0,13,4,53,0,0,0,0,14,8,4,51,0,0,0,0,4,14,0,75,0,0,27,192,0,0,97,61],[0,0,0,0,4,0,0,25,0,0,0,0,6,212,0,25,0,0,0,32,4,64,0,57,0,0,0,0,10,132,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,166,4,53,0,0,0,0,6,228,0,75,0,0,27,185,0,0,65,61],[0,0,0,13,4,16,3,96,0,0,0,0,1,222,0,25,0,0,0,31,6,80,1,143,0,0,0,0,0,1,4,53],[0,0,0,5,8,80,2,114,0,0,27,207,0,0,97,61,0,0,0,0,13,0,0,25,0,0,0,5,10,208,2,16],[0,0,0,0,11,161,0,25,0,0,0,0,10,164,3,79,0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53],[0,0,0,1,13,208,0,57,0,0,0,0,10,141,0,75,0,0,27,199,0,0,65,61,0,0,0,0,10,6,0,75],[0,0,27,222,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,4,132,3,79,0,0,0,0,8,129,0,25],[0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,106,1,207,0,0,0,0,10,106,2,47],[0,0,0,0,4,4,4,59,0,0,1,0,6,96,0,137,0,0,0,0,4,100,2,47,0,0,0,0,4,100,1,207],[0,0,0,0,4,164,1,159,0,0,0,0,0,72,4,53,0,0,0,0,1,81,0,25,0,0,0,0,0,1,4,53],[0,0,0,0,4,7,4,51,0,0,0,0,5,4,0,75,0,0,27,235,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,117,0,25,0,0,0,0,8,8,4,51],[0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,27,228,0,0,65,61,0,0,0,0,1,20,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,12,4,51,0,0,0,0,5,4,0,75,0,0,27,248,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,7,197,0,25],[0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,69,0,75,0,0,27,241,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,4,2,4,51,0,0,0,0,5,4,0,75],[0,0,28,5,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57],[0,0,0,0,7,37,0,25,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,69,0,75],[0,0,27,254,0,0,65,61,0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,2,9,4,51],[0,0,0,0,4,2,0,75,0,0,28,18,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,5,20,0,25],[0,0,0,32,4,64,0,57,0,0,0,0,6,148,0,25,0,0,0,0,6,6,4,51,0,0,0,0,0,101,4,53],[0,0,0,0,5,36,0,75,0,0,28,11,0,0,65,61,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,53],[0,0,0,12,4,0,0,41,0,0,0,0,1,65,0,73,0,0,0,32,2,16,0,138,0,0,0,0,0,36,4,53],[0,0,0,31,1,16,0,57,0,0,0,0,2,49,1,111,0,0,0,0,1,66,0,25,0,0,0,0,2,33,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,3,16,0,156,0,0,1,89,0,0,33,61],[0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65],[0,0,0,9,3,0,0,41,0,0,7,155,2,48,0,156,0,0,0,0,3,1,128,25,0,0,0,64,2,48,2,16],[0,0,0,12,3,0,0,41,0,0,0,0,3,3,4,51,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199],[0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61],[0,0,29,193,0,0,1,61,0,0,7,166,10,112,0,156,0,0,1,89,0,0,33,61,0,0,0,64,0,144,4,63],[0,0,0,1,9,0,0,58,0,0,0,0,0,151,4,53,0,0,0,0,8,128,3,80,0,0,0,0,8,8,4,59],[0,0,0,0,0,132,4,53,0,0,1,193,0,0,97,61,0,0,7,167,8,128,1,151,0,0,0,248,5,80,2,16],[0,0,0,0,5,133,1,159,0,0,7,172,5,80,0,65,0,0,0,0,0,84,4,53,0,0,0,64,4,0,4,61],[0,0,0,32,5,64,0,57,0,0,0,0,8,7,4,51,0,0,0,0,9,8,0,75,0,0,28,84,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,89,0,25,0,0,0,32,9,144,0,57,0,0,0,0,11,121,0,25],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,28,77,0,0,65,61],[0,0,0,0,7,88,0,25,0,0,0,0,0,7,4,53,0,0,0,10,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,9,8,0,75,0,0,28,98,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25],[0,0,0,32,9,144,0,57,0,0,0,10,11,144,0,41,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,137,0,75,0,0,28,91,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53],[0,0,0,9,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,0,9,8,0,75,0,0,28,112,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,9,11,144,0,41],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,28,105,0,0,65,61],[0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,8,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,9,8,0,75,0,0,28,126,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25],[0,0,0,32,9,144,0,57,0,0,0,8,11,144,0,41,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,137,0,75,0,0,28,119,0,0,65,61,0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53],[0,0,0,6,8,0,0,41,0,0,0,0,8,8,4,51,0,0,0,0,9,8,0,75,0,0,28,140,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25,0,0,0,32,9,144,0,57,0,0,0,6,11,144,0,41],[0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53,0,0,0,0,10,137,0,75,0,0,28,133,0,0,65,61],[0,0,0,0,7,120,0,25,0,0,0,0,0,7,4,53,0,0,0,5,8,0,0,41,0,0,0,0,8,8,4,51],[0,0,0,0,9,8,0,75,0,0,28,154,0,0,97,61,0,0,0,0,9,0,0,25,0,0,0,0,10,121,0,25],[0,0,0,32,9,144,0,57,0,0,0,5,11,144,0,41,0,0,0,0,11,11,4,51,0,0,0,0,0,186,4,53],[0,0,0,0,10,137,0,75,0,0,28,147,0,0,65,61,0,0,0,0,6,98,3,79,0,0,0,0,2,120,0,25],[0,0,0,31,7,48,1,143,0,0,0,0,0,2,4,53,0,0,0,5,8,48,2,114,0,0,28,169,0,0,97,61],[0,0,0,0,9,0,0,25,0,0,0,5,10,144,2,16,0,0,0,0,11,162,0,25,0,0,0,0,10,166,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,0,171,4,53,0,0,0,1,9,144,0,57,0,0,0,0,10,137,0,75],[0,0,28,161,0,0,65,61,0,0,0,0,9,7,0,75,0,0,28,184,0,0,97,61,0,0,0,5,8,128,2,16],[0,0,0,0,6,134,3,79,0,0,0,0,8,130,0,25,0,0,0,3,7,112,2,16,0,0,0,0,9,8,4,51],[0,0,0,0,9,121,1,207,0,0,0,0,9,121,2,47,0,0,0,0,6,6,4,59,0,0,1,0,7,112,0,137],[0,0,0,0,6,118,2,47,0,0,0,0,6,118,1,207,0,0,0,0,6,150,1,159,0,0,0,0,0,104,4,53],[0,0,0,0,2,50,0,25,0,0,0,0,0,2,4,53,0,0,0,0,3,1,4,51,0,0,0,0,6,3,0,75],[0,0,28,197,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,0,7,38,0,25,0,0,0,32,6,96,0,57],[0,0,0,0,8,22,0,25,0,0,0,0,8,8,4,51,0,0,0,0,0,135,4,53,0,0,0,0,7,54,0,75],[0,0,28,190,0,0,65,61,0,0,0,0,1,35,0,25,0,0,0,0,0,1,4,53,0,0,0,4,2,0,0,41],[0,0,0,0,2,2,4,51,0,0,0,0,3,2,0,75,0,0,28,211,0,0,97,61,0,0,0,0,3,0,0,25],[0,0,0,0,6,19,0,25,0,0,0,32,3,48,0,57,0,0,0,4,7,48,0,41,0,0,0,0,7,7,4,51],[0,0,0,0,0,118,4,53,0,0,0,0,6,35,0,75,0,0,28,204,0,0,65,61,0,0,0,0,1,18,0,25],[0,0,0,0,0,1,4,53,0,0,0,3,2,0,0,41,0,0,0,0,2,2,4,51,0,0,0,0,3,2,0,75],[0,0,28,225,0,0,97,61,0,0,0,0,3,0,0,25,0,0,0,0,6,19,0,25,0,0,0,32,3,48,0,57],[0,0,0,3,7,48,0,41,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,35,0,75],[0,0,28,218,0,0,65,61,0,0,0,0,1,18,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,65,0,73],[0,0,0,32,2,16,0,138,0,0,0,0,0,36,4,53,0,0,0,31,1,16,0,57,0,0,0,7,2,16,1,127],[0,0,0,0,1,66,0,25,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,7,159,3,16,0,156,0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,7,155,1,0,0,65,0,0,7,155,2,80,0,156,0,0,0,0,5,1,128,25],[0,0,0,64,2,80,2,16,0,0,0,0,3,4,4,51,0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20,0,0,7,155,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159,0,0,7,175,1,16,1,199],[0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,159,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,11,86,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,7,194,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,15,3,0,0,57],[0,0,12,95,0,0,1,61,0,0,7,166,10,208,0,156,0,0,1,89,0,0,33,61,0,0,0,6,6,0,0,41],[0,0,0,64,0,96,4,63,0,0,0,8,6,0,0,41,0,0,0,12,10,0,0,41,0,0,0,0,0,106,4,53],[0,0,0,9,6,0,0,41,0,0,0,0,0,109,4,53,0,0,0,0,10,6,0,75,0,0,1,193,0,0,97,61],[0,0,0,248,10,240,2,16,0,0,0,7,10,160,1,175,0,0,7,172,10,160,0,65,0,0,0,12,6,0,0,41],[0,0,0,0,0,166,4,53,0,0,0,64,6,0,4,61,0,0,0,32,10,96,0,57,0,0,7,175,11,0,0,65],[0,9,0,0,0,10,0,29,0,0,0,0,0,186,4,53,0,12,0,0,0,6,0,29,0,0,0,33,14,96,0,57],[0,0,0,0,15,13,4,51,0,0,0,0,11,15,0,75,0,0,29,47,0,0,97,61,0,0,0,0,11,0,0,25],[0,0,0,0,10,235,0,25,0,0,0,32,11,176,0,57,0,0,0,0,6,219,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,106,4,53,0,0,0,0,6,251,0,75,0,0,29,40,0,0,65,61,0,0,0,0,13,239,0,25],[0,0,0,0,0,13,4,53,0,0,0,0,14,4,4,51,0,0,0,0,6,14,0,75,0,0,29,60,0,0,97,61],[0,0,0,0,11,0,0,25,0,0,0,0,6,219,0,25,0,0,0,32,11,176,0,57,0,0,0,0,10,75,0,25],[0,0,0,0,10,10,4,51,0,0,0,0,0,166,4,53,0,0,0,0,6,235,0,75,0,0,29,53,0,0,65,61],[0,0,0,0,13,222,0,25,0,0,0,0,0,13,4,53,0,0,0,0,14,8,4,51,0,0,0,0,4,14,0,75],[0,0,29,73,0,0,97,61,0,0,0,0,4,0,0,25,0,0,0,0,6,212,0,25,0,0,0,32,4,64,0,57],[0,0,0,0,10,132,0,25,0,0,0,0,10,10,4,51,0,0,0,0,0,166,4,53,0,0,0,0,6,228,0,75],[0,0,29,66,0,0,65,61,0,0,0,13,4,16,3,96,0,0,0,0,1,222,0,25,0,0,0,31,6,80,1,143],[0,0,0,0,0,1,4,53,0,0,0,5,8,80,2,114,0,0,29,88,0,0,97,61,0,0,0,0,13,0,0,25],[0,0,0,5,10,208,2,16,0,0,0,0,11,161,0,25,0,0,0,0,10,164,3,79,0,0,0,0,10,10,4,59],[0,0,0,0,0,171,4,53,0,0,0,1,13,208,0,57,0,0,0,0,10,141,0,75,0,0,29,80,0,0,65,61],[0,0,0,0,10,6,0,75,0,0,29,103,0,0,97,61,0,0,0,5,8,128,2,16,0,0,0,0,4,132,3,79],[0,0,0,0,8,129,0,25,0,0,0,3,6,96,2,16,0,0,0,0,10,8,4,51,0,0,0,0,10,106,1,207],[0,0,0,0,10,106,2,47,0,0,0,0,4,4,4,59,0,0,1,0,6,96,0,137,0,0,0,0,4,100,2,47],[0,0,0,0,4,100,1,207,0,0,0,0,4,164,1,159,0,0,0,0,0,72,4,53,0,0,0,0,1,81,0,25],[0,0,0,0,0,1,4,53,0,0,0,0,4,7,4,51,0,0,0,0,5,4,0,75,0,0,29,116,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57,0,0,0,0,8,117,0,25],[0,0,0,0,8,8,4,51,0,0,0,0,0,134,4,53,0,0,0,0,6,69,0,75,0,0,29,109,0,0,65,61],[0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,4,12,4,51,0,0,0,0,5,4,0,75],[0,0,29,129,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25,0,0,0,32,5,80,0,57],[0,0,0,0,7,197,0,25,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53,0,0,0,0,6,69,0,75],[0,0,29,122,0,0,65,61,0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53,0,0,0,0,4,2,4,51],[0,0,0,0,5,4,0,75,0,0,29,142,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,0,6,21,0,25],[0,0,0,32,5,80,0,57,0,0,0,0,7,37,0,25,0,0,0,0,7,7,4,51,0,0,0,0,0,118,4,53],[0,0,0,0,6,69,0,75,0,0,29,135,0,0,65,61,0,0,0,0,1,20,0,25,0,0,0,0,0,1,4,53],[0,0,0,0,2,9,4,51,0,0,0,0,4,2,0,75,0,0,29,155,0,0,97,61,0,0,0,0,4,0,0,25],[0,0,0,0,5,20,0,25,0,0,0,32,4,64,0,57,0,0,0,0,6,148,0,25,0,0,0,0,6,6,4,51],[0,0,0,0,0,101,4,53,0,0,0,0,5,36,0,75,0,0,29,148,0,0,65,61,0,0,0,0,1,18,0,25],[0,0,0,0,0,1,4,53,0,0,0,12,4,0,0,41,0,0,0,0,1,65,0,73,0,0,0,32,2,16,0,138],[0,0,0,0,0,36,4,53,0,0,0,31,1,16,0,57,0,0,0,0,2,49,1,111,0,0,0,0,1,66,0,25],[0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,7,159,3,16,0,156],[0,0,1,89,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,89,0,0,193,61,0,0,0,64,0,16,4,63],[0,0,7,155,1,0,0,65,0,0,0,9,3,0,0,41,0,0,7,155,2,48,0,156,0,0,0,0,3,1,128,25],[0,0,0,64,2,48,2,16,0,0,0,12,3,0,0,41,0,0,0,0,3,3,4,51,0,0,7,155,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,96,3,48,2,16,0,0,0,0,2,35,1,159,0,0,0,0,3,0,4,20],[0,0,7,155,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159],[0,0,7,175,1,16,1,199,0,0,128,16,2,0,0,57,30,104,30,94,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,159,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,2,0,4,21,0,0,0,10,2,32,0,105],[0,0,0,0,2,0,0,2,0,0,11,86,0,0,1,61,0,0,0,0,3,0,4,20,0,0,0,0,4,18,0,25],[0,0,0,0,2,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,7,155,2,16,1,151],[0,0,0,1,1,80,1,144,0,0,30,31,0,0,193,61,0,0,0,0,1,0,0,49,0,0,0,0,5,65,0,75],[0,0,30,31,0,0,65,61,0,0,0,1,2,32,3,103,0,0,7,176,5,48,0,156,0,0,30,35,0,0,129,61],[0,0,0,0,1,65,0,73,0,0,7,155,1,16,1,151,0,0,0,0,1,18,3,223,0,0,0,192,2,48,2,16],[0,0,7,177,2,32,1,151,0,0,7,178,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57],[30,104,30,99,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,7,155,3,48,1,151],[0,0,0,1,2,32,1,144,0,0,30,42,0,0,97,61,0,0,0,63,2,48,0,57,0,0,7,179,4,32,1,151],[0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,7,159,6,64,0,156,0,0,30,69,0,0,33,61,0,0,0,1,5,80,1,144],[0,0,30,69,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57],[0,0,0,5,5,80,2,114,0,0,29,253,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,29,245,0,0,65,61,0,0,0,0,5,0,0,75,0,0,29,255,0,0,97,61,0,0,0,31,5,48,1,143],[0,0,0,5,3,48,2,114,0,0,30,11,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,30,3,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,30,26,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140],[0,0,30,75,0,0,193,61,0,0,0,0,1,4,4,51,0,0,0,0,0,1,4,45,0,0,7,195,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,30,72,0,0,1,61,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,7,191,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,8,3,0,0,57,0,0,30,81,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,30,53,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,30,46,0,0,65,61,0,0,0,0,5,4,0,75,0,0,30,67,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,30,106,0,1,4,48,0,0,7,195,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,7,196,1,0,0,65,0,0,30,106,0,1,4,48,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,7,181,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53,0,0,7,161,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,7,155,2,0,0,65],[0,0,7,155,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,7,182,1,16,1,199],[0,0,30,106,0,1,4,48,0,0,0,0,0,1,4,47,0,0,30,97,0,33,4,35,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,30,102,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,30,104,0,0,4,50,0,0,30,105,0,1,4,46,0,0,30,106,0,1,4,48,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[235,228,163,215,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[69,110,99,111,100,105,110,103,32,117,110,115,117,112,112,111,114,116,101,100,32,116,120,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[154,138,5,146,172,137,197,173,59,198,223,130,36,193,123,72,89,118,245,151,223,16,78,226,13,13,244,21,36,31,103,11],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,191],[0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[148,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[184,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[248,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[7,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[132,142,27,250,26,196,227,87,107,114,139,218,103,33,178,21,199,10,119,153,165,180,134,98,130,167,27,171,149,75,170,200],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,254,31],[194,248,120,113,118,184,172,107,247,33,91,74,220,193,224,105,191,74,184,45,154,177,223,5,165,122,145,212,37,147,91,110],[173,124,91,239,2,120,22,168,0,218,23,54,68,79,181,138,128,126,244,201,96,59,120,72,103,63,126,58,104,235,20,165],[25,180,83,206,69,170,170,243,163,0,245,169,236,149,134,155,79,40,171,16,67,11,87,46,226,24,195,166,165,224,125,111],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,95],[25,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,127],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[85,110,115,117,112,112,111,114,116,101,100,32,116,120,32,116,121,112,101,0,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,118,97,108,105,100,32,118,32,118,97,108,117,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,159],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[161,135,70,180,171,129,132,196,113,180,222,52,244,51,34,63,179,4,137,162,144,246,227,135,212,103,1,116,178,89,133,86]],"0x000000000000000000000000000000000000800e":[[0,2,0,0,0,0,0,2,0,12,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,4,48,2,112,0,0,1,44,0,64,1,157,0,0,0,128,3,0,0,57,0,0,0,64,0,48,4,63],[0,2,0,0,0,4,0,29,0,0,1,44,3,64,1,151,0,0,0,1,2,32,1,144,0,0,1,242,0,0,193,61],[0,0,0,4,2,48,0,140,0,0,2,74,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,1,46,4,32,0,156,0,0,1,128,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,128,2,32,0,140],[0,0,2,74,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,8,2,4,59,0,0,0,68,2,16,3,112],[0,0,0,0,4,2,4,59,0,0,0,36,2,16,3,112,0,0,0,0,14,2,4,59,0,7,0,0,0,4,0,29],[0,0,1,48,2,64,0,156,0,0,2,74,0,0,33,61,0,0,0,7,2,0,0,41,0,0,0,35,2,32,0,57],[0,0,1,49,4,0,0,65,0,0,0,0,5,50,0,75,0,0,0,0,5,0,0,25,0,0,0,0,5,4,128,25],[0,0,1,49,2,32,1,151,0,0,0,0,6,2,0,75,0,0,0,0,4,0,128,25,0,0,1,49,2,32,0,156],[0,0,0,0,4,5,192,25,0,0,0,0,2,4,0,75,0,0,2,74,0,0,193,61,0,0,0,7,2,0,0,41],[0,0,0,4,2,32,0,57,0,0,0,0,2,33,3,79,0,0,0,0,6,2,4,59,0,0,1,48,2,96,0,156],[0,0,2,74,0,0,33,61,0,0,0,7,2,0,0,41,0,0,0,36,5,32,0,57,0,1,0,0,0,86,0,29],[0,0,0,1,2,48,0,108,0,0,2,74,0,0,65,61,0,0,0,100,2,16,3,112,0,0,0,0,2,2,4,59],[0,9,0,0,0,2,0,29,0,0,1,48,2,32,0,156,0,0,2,74,0,0,33,61,0,0,0,9,2,0,0,41],[0,0,0,35,2,32,0,57,0,0,1,49,4,0,0,65,0,0,0,0,7,50,0,75,0,0,0,0,7,0,0,25],[0,0,0,0,7,4,128,25,0,0,1,49,2,32,1,151,0,0,0,0,9,2,0,75,0,0,0,0,4,0,128,25],[0,0,1,49,2,32,0,156,0,0,0,0,4,7,192,25,0,0,0,0,2,4,0,75,0,0,2,74,0,0,193,61],[0,0,0,9,2,0,0,41,0,0,0,4,2,32,0,57,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59],[0,11,0,0,0,2,0,29,0,0,1,48,2,32,0,156,0,0,2,74,0,0,33,61,0,0,0,9,2,0,0,41],[0,0,0,36,4,32,0,57,0,10,0,0,0,4,0,29,0,0,0,11,2,64,0,41,0,0,0,0,2,50,0,75],[0,0,2,74,0,0,33,61,0,0,0,0,2,0,4,17,0,0,128,8,2,32,0,140,0,0,1,250,0,0,193,61],[0,0,0,9,2,224,0,140,0,0,2,2,0,0,129,61,0,12,0,2,0,0,0,61,0,0,1,16,41,128,0,201],[0,0,1,17,10,0,0,138,0,8,0,0,0,0,0,29,0,0,0,0,7,0,0,25,0,6,0,0,0,14,0,29],[0,0,0,0,2,8,0,75,0,0,0,101,0,0,97,61,0,0,0,0,50,137,0,217,0,0,1,16,2,32,0,140],[0,0,2,239,0,0,193,61,0,0,0,0,2,151,0,75,0,0,0,206,0,0,129,61,0,0,0,0,2,167,0,75],[0,0,2,239,0,0,33,61,0,0,1,16,4,112,0,57,0,0,0,0,2,100,0,75,0,0,2,74,0,0,33,61],[0,0,0,0,2,87,0,25,0,0,0,60,2,32,0,57,0,0,0,0,3,33,3,79,0,0,0,0,3,3,4,59],[0,0,1,48,3,48,1,152,0,0,0,0,7,4,0,25,0,0,0,96,0,0,193,61,0,0,0,1,15,0,0,138],[0,0,0,8,3,240,0,107,0,0,2,239,0,0,97,61,0,0,0,12,11,0,0,41,0,0,0,10,3,176,0,41],[0,0,0,0,7,49,3,79,0,0,0,8,3,32,0,138,0,0,0,0,2,49,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,2,2,4,59,0,0,0,0,2,114,0,75,0,0,2,42,0,0,193,61,0,0,0,33,2,0,0,138],[0,0,0,0,2,43,0,75,0,0,2,239,0,0,33,61,0,0,0,12,11,0,0,41,0,0,0,32,2,176,0,57],[0,0,0,11,7,32,0,108,0,0,1,86,0,0,129,61,0,0,0,10,2,32,0,41,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,251,7,32,2,112,0,0,0,248,2,32,2,112,0,0,0,7,13,32,1,144],[0,0,0,32,7,0,96,57,0,0,0,33,2,176,0,57,0,12,0,0,0,39,0,30,0,0,2,239,0,0,65,61],[0,0,0,12,12,0,0,41,0,0,0,11,12,192,0,108,0,0,2,74,0,0,33,61,0,0,0,10,2,32,0,41],[0,0,0,72,12,48,0,57,0,0,0,0,12,193,3,79,0,0,0,40,3,48,0,57,0,0,0,0,14,49,3,79],[0,0,0,0,2,33,3,79,0,0,0,0,3,2,4,59,0,0,0,0,2,14,4,59,0,5,0,0,0,2,0,29],[0,0,0,6,14,0,0,41,0,0,0,0,11,12,4,59,0,0,0,31,2,112,0,140,0,0,0,3,2,112,2,16],[0,0,0,171,0,0,33,61,0,0,1,0,12,32,0,137,0,0,0,0,12,207,1,207,0,0,0,0,14,32,0,73],[0,0,1,0,15,0,0,138,0,0,0,0,14,254,0,75,0,0,0,6,14,0,0,41,0,0,0,0,12,0,64,25],[0,0,0,0,3,195,1,111,0,0,0,0,12,7,0,75,0,0,0,204,0,0,97,61,0,0,1,0,12,32,0,140],[0,0,2,239,0,0,33,61,0,0,0,0,199,114,0,217,0,0,0,8,7,112,0,140,0,0,2,239,0,0,193,61],[0,0,1,0,7,32,0,137,0,0,0,0,3,115,2,47,0,0,0,0,2,2,0,75,0,0,0,0,3,0,96,25],[0,0,0,8,2,0,0,41,0,8,0,1,0,32,0,61,0,0,0,0,2,13,0,75,0,0,0,193,0,0,97,61],[0,0,0,3,2,208,0,140,0,0,0,193,0,0,97,61,0,0,0,1,2,208,0,140,0,0,0,197,0,0,193,61],[0,0,0,5,2,48,0,41,0,0,0,0,2,178,0,75,0,0,0,0,7,4,0,25,0,0,0,96,0,0,97,61],[0,0,1,108,0,0,1,61,0,0,0,0,2,179,0,75,0,0,0,0,7,4,0,25,0,0,0,96,0,0,97,61],[0,0,1,90,0,0,1,61,0,0,0,2,2,208,0,140,0,0,1,100,0,0,193,61,0,0,0,5,2,48,0,105],[0,0,0,0,2,178,0,75,0,0,0,0,7,4,0,25,0,0,0,96,0,0,97,61,0,0,1,118,0,0,1,61],[0,0,0,0,3,0,0,25,0,0,0,180,0,0,1,61,0,0,0,9,2,0,0,41,0,0,0,6,2,32,0,57],[0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59,0,0,255,255,2,32,1,143,0,0,0,8,2,32,0,107],[0,0,2,12,0,0,193,61,0,0,0,3,3,224,2,16,0,0,1,0,2,48,0,137,0,0,0,1,4,0,0,138],[0,8,0,0,0,2,0,29,0,4,0,0,0,4,0,29,0,0,0,0,4,36,1,207,0,0,0,0,2,48,0,73],[0,3,1,0,0,0,0,146,0,0,0,3,2,32,0,108,0,0,0,0,4,0,64,25,0,5,0,0,0,4,0,29],[0,9,0,0,0,3,0,29,0,0,1,0,2,48,0,140,0,0,2,22,0,0,33,61,0,0,0,0,3,0,0,25],[0,0,0,232,0,0,1,61,0,0,0,0,2,210,0,75,0,0,0,0,3,4,0,25,0,0,1,90,0,0,193,61],[0,0,0,0,2,8,0,75,0,0,0,237,0,0,97,61,0,0,0,0,66,137,0,217,0,0,1,16,2,32,0,140],[0,0,2,239,0,0,193,61,0,0,0,0,2,147,0,75,0,0,2,76,0,0,129,61,0,0,0,0,2,163,0,75],[0,0,2,239,0,0,33,61,0,0,1,16,4,48,0,57,0,0,0,0,2,100,0,75,0,0,2,74,0,0,33,61],[0,0,0,0,2,83,0,25,0,0,0,60,13,32,0,57,0,0,0,0,2,209,3,79,0,0,0,0,2,2,4,59],[0,0,1,48,7,32,1,152,0,0,0,0,3,4,0,25,0,0,0,232,0,0,97,61,0,0,0,12,15,224,0,42],[0,0,2,239,0,0,65,61,0,0,0,11,2,240,0,108,0,0,2,74,0,0,33,61,0,0,0,10,3,0,0,41],[0,0,0,12,2,48,0,41,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59,0,0,0,31,3,224,0,140],[0,0,1,8,0,0,33,61,0,0,0,5,2,32,1,127,0,0,0,0,3,14,0,75,0,0,2,231,0,0,97,61],[0,0,0,9,179,224,0,249,0,0,0,8,3,48,0,140,0,0,2,239,0,0,193,61,0,0,0,9,3,0,0,107],[0,0,2,231,0,0,97,61,0,0,0,8,2,32,2,80,0,0,0,0,2,39,0,75,0,0,2,231,0,0,193,61],[0,0,0,11,2,240,0,108,0,0,1,86,0,0,129,61,0,0,0,10,2,240,0,41,0,0,0,0,2,33,3,79],[0,0,0,0,2,2,4,59,0,0,0,251,7,32,2,112,0,0,0,248,2,32,2,112,0,0,0,7,3,32,1,144],[0,0,0,32,7,0,96,57,0,0,0,1,2,240,0,57,0,12,0,0,0,39,0,29,0,0,0,12,12,240,0,107],[0,0,2,239,0,0,161,61,0,0,0,12,12,0,0,41,0,0,0,11,12,192,0,108,0,0,2,74,0,0,33,61],[0,0,0,10,2,32,0,41,0,0,0,64,12,208,0,57,0,0,0,0,12,193,3,79,0,0,0,32,13,208,0,57],[0,0,0,0,13,209,3,79,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59,0,0,0,0,15,13,4,59],[0,0,0,0,13,12,4,59,0,0,0,31,12,112,0,140,0,0,0,3,12,112,2,16,0,0,1,57,0,0,33,61],[0,0,1,0,14,192,0,137,0,0,0,4,14,224,1,239,0,0,0,0,11,192,0,73,0,7,0,0,0,13,0,29],[0,0,0,0,13,15,0,25,0,0,0,3,11,176,0,108,0,0,0,0,15,13,0,25,0,0,0,7,13,0,0,41],[0,0,0,0,14,0,64,25,0,0,0,0,2,226,1,111,0,0,0,6,14,0,0,41,0,0,0,0,11,7,0,75],[0,0,1,84,0,0,97,61,0,0,1,0,11,192,0,140,0,0,2,239,0,0,33,61,0,0,0,0,183,124,0,217],[0,0,0,8,7,112,0,140,0,0,2,239,0,0,193,61,0,0,1,0,7,192,0,137,0,0,0,0,2,114,2,47],[0,0,0,0,7,12,0,75,0,0,0,0,2,0,96,25,0,0,0,0,7,3,0,75,0,0,0,229,0,0,97,61],[0,0,0,3,7,48,0,140,0,0,0,229,0,0,97,61,0,0,0,1,7,48,0,140,0,0,1,77,0,0,193,61],[0,0,0,0,2,242,0,25,0,0,0,0,2,210,0,75,0,0,0,0,3,4,0,25,0,0,0,232,0,0,97,61],[0,0,1,108,0,0,1,61,0,0,0,2,3,48,0,140,0,0,1,100,0,0,193,61,0,0,0,0,2,47,0,73],[0,0,0,0,2,210,0,75,0,0,0,0,3,4,0,25,0,0,0,232,0,0,97,61,0,0,1,118,0,0,1,61],[0,0,0,0,2,0,0,25,0,0,1,66,0,0,1,61,0,0,1,88,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,50,1,0,0,57,0,0,2,242,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,58,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,92,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,93,1,0,0,65,0,0,2,101,0,0,1,61],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,21,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,94,1,0,0,65,0,0,2,89,0,0,1,61],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,46,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,97,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,1,98,1,0,0,65,0,0,2,101,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,47,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,95,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,96,1,0,0,65,0,0,2,101,0,0,1,61],[0,0,1,47,2,32,0,156,0,0,2,74,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140],[0,0,2,74,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,5,2,4,59,0,0,1,48,2,80,0,156],[0,0,2,74,0,0,33,61,0,0,0,35,2,80,0,57,0,0,1,49,4,0,0,65,0,0,0,0,6,50,0,75],[0,0,0,0,6,0,0,25,0,0,0,0,6,4,128,25,0,0,1,49,2,32,1,151,0,0,0,0,7,2,0,75],[0,0,0,0,4,0,128,25,0,0,1,49,2,32,0,156,0,0,0,0,4,6,192,25,0,0,0,0,2,4,0,75],[0,0,2,74,0,0,193,61,0,0,0,4,2,80,0,57,0,0,0,0,2,33,3,79,0,0,0,0,2,2,4,59],[0,11,0,0,0,2,0,29,0,0,1,48,2,32,0,156,0,0,2,74,0,0,33,61,0,0,0,36,4,80,0,57],[0,0,0,11,2,64,0,41,0,0,0,0,6,35,0,75,0,0,2,74,0,0,65,61,0,0,0,36,6,16,3,112],[0,0,0,0,6,6,4,59,0,0,1,48,7,96,0,156,0,0,2,74,0,0,33,61,0,0,0,35,7,96,0,57],[0,0,1,49,8,0,0,65,0,0,0,0,9,55,0,75,0,0,0,0,9,0,0,25,0,0,0,0,9,8,128,25],[0,0,1,49,7,112,1,151,0,0,0,0,10,7,0,75,0,0,0,0,8,0,128,25,0,0,1,49,7,112,0,156],[0,0,0,0,8,9,192,25,0,0,0,0,7,8,0,75,0,0,2,74,0,0,193,61,0,0,0,4,7,96,0,57],[0,0,0,0,8,113,3,79,0,0,0,0,8,8,4,59,0,10,0,0,0,8,0,29,0,0,1,48,8,128,0,156],[0,0,2,74,0,0,33,61,0,0,0,36,9,96,0,57,0,9,0,0,0,9,0,29,0,0,0,10,8,144,0,41],[0,0,0,0,3,56,0,75,0,0,2,74,0,0,33,61,0,0,0,0,3,0,4,17,0,0,128,1,3,48,0,140],[0,0,2,245,0,0,193,61,0,0,0,2,3,112,0,57,0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59],[0,0,0,3,3,48,2,16,0,0,1,53,3,48,1,151,0,0,0,2,8,48,1,191,0,0,0,10,7,128,0,107],[0,0,2,74,0,0,65,61,0,0,0,10,7,128,0,105,0,0,0,2,9,112,2,16,0,0,0,11,9,144,0,108],[0,0,2,253,0,0,193,61,0,0,0,10,9,128,0,107,0,0,1,228,0,0,97,61,0,0,0,6,9,96,0,57],[0,0,0,0,8,152,0,25,0,0,0,14,6,96,0,57,0,0,0,12,5,80,0,57,0,0,0,0,9,0,0,25],[0,0,0,0,10,152,0,25,0,0,0,0,10,161,3,79,0,0,0,0,10,10,4,59,0,0,0,3,10,160,2,16],[0,0,1,53,10,160,1,151,0,0,0,0,11,58,0,75,0,0,3,19,0,0,129,61,0,0,0,0,10,166,0,25],[0,0,0,2,11,144,2,16,0,0,0,0,11,181,0,25,0,0,0,0,11,177,3,79,0,0,0,0,10,161,3,79],[0,0,0,0,10,10,4,59,0,0,0,0,11,11,4,59,0,0,0,0,10,186,1,63,0,0,1,48,10,160,1,152],[0,0,3,29,0,0,193,61,0,0,0,2,9,144,0,57,0,0,0,0,10,121,0,75,0,0,1,208,0,0,65,61],[0,0,0,11,3,0,0,41,0,0,0,31,3,48,1,144,0,0,3,11,0,0,193,61,0,0,0,11,3,0,0,41],[0,0,1,64,3,48,0,156,0,0,3,39,0,0,65,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,2,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,80,1,0,0,65,0,0,2,89,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,2,74,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,1,45,1,0,0,65,0,0,4,170,0,1,4,46,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,81,1,0,0,65,0,0,2,89,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,35,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,99,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,100,1,0,0,65,0,0,2,101,0,0,1,61],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,41,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,82,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,1,83,1,0,0,65,0,0,2,101,0,0,1,61,0,0,0,0,2,8,0,75,0,0,2,50,0,0,193,61],[0,0,0,7,2,0,0,41,0,0,0,96,2,32,0,57,0,0,0,0,3,0,0,25,0,0,0,6,8,0,0,41],[0,0,0,0,4,147,0,75,0,0,2,76,0,0,129,61,0,0,0,0,4,163,0,75,0,0,2,239,0,0,33,61],[0,0,1,16,4,48,0,57,0,0,0,0,7,100,0,75,0,0,2,74,0,0,33,61,0,0,0,0,3,50,0,25],[0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59,0,0,1,48,3,48,1,152,0,0,0,0,3,4,0,25],[0,0,2,28,0,0,97,61,0,0,2,70,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,24,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,91,1,0,0,65,0,0,2,89,0,0,1,61,0,0,0,0,50,137,0,217,0,0,1,16,2,32,0,140],[0,0,0,6,8,0,0,41,0,0,2,239,0,0,193,61,0,0,0,7,2,0,0,41,0,0,0,96,2,32,0,57],[0,0,0,0,3,0,0,25,0,0,0,0,4,147,0,75,0,0,2,76,0,0,129,61,0,0,0,0,4,163,0,75],[0,0,2,239,0,0,33,61,0,0,1,16,4,48,0,57,0,0,0,0,7,100,0,75,0,0,2,74,0,0,33,61],[0,0,0,0,3,50,0,25,0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59,0,0,1,48,3,48,1,152],[0,0,0,0,3,4,0,25,0,0,2,57,0,0,97,61,0,0,0,12,1,128,0,42,0,0,2,239,0,0,65,61],[0,0,0,11,1,16,0,108,0,0,2,229,0,0,161,61,0,0,0,0,1,0,0,25,0,0,4,171,0,1,4,48],[0,0,0,12,3,0,0,41,0,0,0,11,2,48,0,108,0,0,2,92,0,0,193,61,0,0,0,0,2,0,4,20],[0,0,1,86,3,32,0,156,0,0,2,104,0,0,65,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,8,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,89,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,52,1,0,0,65,0,0,4,171,0,1,4,48],[0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,35,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,84,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,1,85,1,0,0,65,0,0,0,228,0,16,4,63,0,0,1,60,1,0,0,65,0,0,4,171,0,1,4,48],[0,0,1,44,3,80,1,151,0,0,0,0,1,49,3,79,0,0,0,1,4,0,0,41,0,0,0,2,3,64,0,105],[0,0,1,44,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,192,2,32,2,16,0,0,1,65,2,32,1,151],[0,0,1,66,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,4,169,4,164,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,1,44,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,2,189,0,0,97,61,0,0,0,63,2,48,0,57,0,0,1,67,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,1,48,6,64,0,156,0,0,4,32,0,0,33,61,0,0,0,1,5,80,1,144,0,0,4,32,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114],[0,0,2,148,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75,0,0,2,140,0,0,65,61],[0,0,0,0,5,0,0,75,0,0,2,150,0,0,97,61,0,0,0,31,5,48,1,143,0,0,0,5,3,48,2,114],[0,0,2,162,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,54,0,75,0,0,2,154,0,0,65,61,0,0,0,0,6,5,0,75,0,0,2,177,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25,0,0,0,3,5,80,2,16],[0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,19,4,53,0,0,1,44,3,0,0,65,0,0,0,64,1,0,4,61,0,0,1,44,5,16,0,156],[0,0,0,0,3,1,64,25,0,0,0,64,3,48,2,16,0,0,0,0,2,2,4,51,0,0,0,32,2,32,0,140],[0,0,2,216,0,0,193,61,0,0,0,0,2,4,4,51,0,0,0,0,0,33,4,53,0,0,1,78,1,48,1,199],[0,0,4,170,0,1,4,46,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,2,200,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,2,193,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,2,214,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,4,171,0,1,4,48],[0,0,0,68,2,16,0,57,0,0,1,87,4,0,0,65,0,0,0,0,0,66,4,53,0,0,0,36,2,16,0,57],[0,0,0,31,4,0,0,57,0,0,0,0,0,66,4,53,0,0,1,50,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,1,16,0,57,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,1,69,1,48,1,199],[0,0,4,171,0,1,4,48,0,0,0,0,1,8,0,75,0,0,2,239,0,0,193,61,0,0,1,50,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,21,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,90,1,0,0,65,0,0,2,89,0,0,1,61,0,0,1,88,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57,0,0,0,4,0,16,4,63,0,0,1,77,1,0,0,65],[0,0,4,171,0,1,4,48,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,51,1,0,0,65],[0,0,2,89,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,72,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,54,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,1,55,1,0,0,65,0,0,0,228,0,16,4,63,0,0,1,56,1,0,0,65],[0,0,1,4,0,16,4,63,0,0,1,57,1,0,0,65,0,0,4,171,0,1,4,48,0,0,1,50,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,2,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,63,1,0,0,65,0,0,2,89,0,0,1,61,0,0,1,50,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,1,58,1,0,0,65,0,0,0,196,0,16,4,63,0,0,1,59,1,0,0,65],[0,0,2,101,0,0,1,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,50,1,0,0,57,0,0,0,164,0,16,4,63,0,0,1,61,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,1,62,1,0,0,65,0,0,2,101,0,0,1,61,0,0,0,11,3,0,0,41],[0,0,0,32,3,48,1,144,0,0,3,50,0,0,193,61,0,0,1,50,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,2,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,1,79,1,0,0,65,0,0,2,89,0,0,1,61,0,0,0,0,3,0,4,20,0,0,1,44,5,48,0,156],[0,0,2,82,0,0,33,61,0,0,1,44,4,64,1,151,0,0,0,0,1,65,3,79,0,0,0,2,2,32,0,105],[0,0,1,44,2,32,1,151,0,0,0,0,1,33,3,223,0,0,0,192,2,48,2,16,0,0,1,65,2,32,1,151],[0,0,1,66,2,32,1,199,0,0,0,0,1,33,3,175,0,0,0,2,2,0,0,57,4,169,4,164,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,1,44,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,4,36,0,0,97,61,0,0,0,63,2,48,0,57,0,0,1,67,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,1,48,6,64,0,156,0,0,4,32,0,0,33,61,0,0,0,1,5,80,1,144,0,0,4,32,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,5,50,4,54,0,0,0,1,4,0,3,103,0,0,0,31,6,48,0,57],[0,0,0,5,6,96,2,114,0,0,3,96,0,0,97,61,0,0,0,0,7,64,3,104,0,0,0,0,8,0,0,25],[0,0,0,5,9,128,2,16,0,0,0,0,10,149,0,25,0,0,0,0,9,151,3,79,0,0,0,0,9,9,4,59],[0,0,0,0,0,154,4,53,0,0,0,1,8,128,0,57,0,0,0,0,9,104,0,75,0,0,3,88,0,0,65,61],[0,0,0,0,6,0,0,75,0,0,3,98,0,0,97,61,0,0,0,31,6,48,1,143,0,0,0,5,3,48,2,114],[0,0,3,110,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,133,0,25],[0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,55,0,75,0,0,3,102,0,0,65,61,0,0,0,0,7,6,0,75,0,0,3,125,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,53,0,25,0,0,0,3,6,96,2,16],[0,0,0,0,7,3,4,51,0,0,0,0,7,103,1,207,0,0,0,0,7,103,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,6,96,0,137,0,0,0,0,1,97,2,47,0,0,0,0,1,97,1,207,0,0,0,0,1,113,1,159],[0,0,0,0,0,19,4,53,0,0,0,64,6,0,4,61,0,0,0,68,1,96,0,57,0,0,0,36,3,96,0,57],[0,12,0,0,0,6,0,29,0,0,0,4,6,96,0,57,0,0,0,0,2,2,4,51,0,0,0,32,2,32,0,140],[0,0,4,63,0,0,193,61,0,0,0,0,5,5,4,51,0,0,1,70,2,0,0,65,0,0,0,12,7,0,0,41],[0,0,0,0,0,39,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,38,4,53,0,0,0,10,6,0,0,41],[0,0,0,0,0,99,4,53,0,0,0,9,2,64,3,96,0,0,1,71,3,80,1,151,0,0,0,11,4,0,0,41],[0,0,0,219,4,64,2,16,0,0,1,72,4,64,1,151,0,0,0,0,4,52,1,159,0,0,0,31,3,96,1,143],[0,11,1,73,0,64,1,203,0,0,0,5,4,96,2,114,0,0,3,160,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,97,0,25,0,0,0,0,6,98,3,79,0,0,0,0,6,6,4,59],[0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75,0,0,3,152,0,0,65,61],[0,0,0,0,5,3,0,75,0,0,3,175,0,0,97,61,0,0,0,5,4,64,2,16,0,0,0,0,2,66,3,79],[0,0,0,0,4,65,0,25,0,0,0,3,3,48,2,16,0,0,0,0,5,4,4,51,0,0,0,0,5,53,1,207],[0,0,0,0,5,53,2,47,0,0,0,0,2,2,4,59,0,0,1,0,3,48,0,137,0,0,0,0,2,50,2,47],[0,0,0,0,2,50,1,207,0,0,0,0,2,82,1,159,0,0,0,0,0,36,4,53,0,0,0,10,2,0,0,41],[0,0,0,0,1,33,0,25,0,0,0,0,0,1,4,53,0,0,0,31,1,32,0,57,0,0,0,32,2,0,0,138],[0,0,0,0,1,33,1,111,0,0,1,44,2,0,0,65,0,0,0,12,4,0,0,41,0,0,1,44,3,64,0,156],[0,0,0,0,3,2,0,25,0,0,0,0,3,4,64,25,0,0,0,64,3,48,2,16,0,0,0,68,1,16,0,57],[0,0,1,44,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,19,1,159],[0,0,0,0,3,0,4,20,0,0,1,44,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,128,8,2,0,0,57,4,169,4,154,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,1,44,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,3,217,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,12,9,128,0,41,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,3,209,0,0,65,61,0,0,0,0,7,5,0,75,0,0,3,232,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,12,6,96,0,41,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,0,0,1,2,32,1,144,0,0,4,78,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143],[0,0,0,12,1,32,0,41,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,1,48,4,16,0,156,0,0,4,32,0,0,33,61,0,0,0,1,2,32,1,144,0,0,4,32,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140,0,0,2,74,0,0,65,61,0,0,1,74,1,0,0,65],[0,0,0,0,0,16,4,57,0,0,128,4,1,0,0,57,0,0,0,4,0,16,4,67,0,0,1,44,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,1,44,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,1,75,1,16,1,199,0,0,128,2,2,0,0,57,4,169,4,159,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,4,113,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75,0,0,2,74,0,0,97,61],[0,0,0,64,4,0,4,61,0,0,1,76,1,0,0,65,0,0,0,0,0,20,4,53,0,0,0,4,1,64,0,57],[0,0,0,11,2,0,0,41,0,0,0,0,0,33,4,53,0,0,1,44,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,1,44,3,32,0,156,0,0,0,0,2,1,128,25,0,0,1,44,3,64,0,156,0,12,0,0,0,4,0,29],[0,0,0,0,1,4,64,25,0,10,0,64,0,16,2,24,0,0,0,192,1,32,2,16,0,0,0,10,1,16,1,175],[0,0,1,77,1,16,1,199,0,0,128,4,2,0,0,57,4,169,4,154,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,4,114,0,0,97,61,0,0,0,12,1,0,0,41,0,0,1,48,1,16,0,156,0,0,4,146,0,0,161,61],[0,0,1,88,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,2,242,0,0,1,61],[0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,4,47,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,4,40,0,0,65,61,0,0,0,0,5,4,0,75],[0,0,4,61,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51],[0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159],[0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,4,171,0,1,4,48,0,0,1,50,2,0,0,65],[0,0,0,12,4,0,0,41,0,0,0,0,0,36,4,53,0,0,0,32,2,0,0,57,0,0,0,0,0,38,4,53],[0,0,0,25,2,0,0,57,0,0,0,0,0,35,4,53,0,0,1,68,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,1,44,1,0,0,65,0,0,1,44,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16],[0,0,1,69,1,16,1,199,0,0,4,171,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,4,91,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,4,83,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,4,106,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,1,44,1,0,0,65,0,0,1,44,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159],[0,0,4,171,0,1,4,48,0,0,0,0,0,1,4,47,0,0,0,64,2,0,4,61,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,31,4,48,1,143,0,0,1,44,3,48,1,151,0,0,0,5,5,48,2,114],[0,0,4,130,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,4,122,0,0,65,61,0,0,0,0,6,4,0,75,0,0,4,145,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,4,106,0,0,1,61,0,0,0,12,2,0,0,41,0,0,0,64,0,32,4,63],[0,0,0,11,1,0,0,41,0,0,0,0,0,18,4,53,0,0,0,10,1,0,0,41,0,0,1,78,1,16,1,199],[0,0,4,170,0,1,4,46,0,0,0,0,0,1,4,47,0,0,4,157,0,33,4,33,0,0,0,1,2,0,0,57],[0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,4,162,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,4,167,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,4,169,0,0,4,50,0,0,4,170,0,1,4,46,0,0,4,171,0,1,4,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,6,216,181],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,245,230,154,71],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,255,248],[69,110,99,111,100,101,100,32,100,97,116,97,32,108,101,110,103,116,104,32,115,104,111,117,108,100,32,98,101,32,52,32],[116,105,109,101,115,32,115,104,111,114,116,101,114,32,116,104,97,110,32,116,104,101,32,111,114,105,103,105,110,97,108,32],[98,121,116,101,99,111,100,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,128,0,0,0,0,0,0,0,0],[69,110,99,111,100,101,100,32,99,104,117,110,107,32,105,110,100,101,120,32,105,115,32,111,117,116,32,111,102,32,98,111],[117,110,100,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[69,110,99,111,100,101,100,32,99,104,117,110,107,32,100,111,101,115,32,110,111,116,32,109,97,116,99,104,32,116,104,101],[32,111,114,105,103,105,110,97,108,32,98,121,116,101,99,111,100,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[112,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0],[0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[115,104,97,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[98,248,75,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[254,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[121,196,249,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[112,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[112,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,97,112,112,114,111,112,114,105,97,116,101,32,99,97,108,108,101,114,0,0,0,0,0,0,0,0,0,0,0,0],[73,110,99,111,114,114,101,99,116,32,110,117,109,98,101,114,32,111,102,32,105,110,105,116,105,97,108,32,115,116,111,114],[97,103,101,32,100,105,102,102,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[69,120,116,114,97,32,100,97,116,97,32,105,110,32,95,99,111,109,112,114,101,115,115,101,100,83,116,97,116,101,68,105],[102,102,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[114,119,58,32,101,110,117,109,32,107,101,121,32,109,105,115,109,97,116,99,104,0,0,0,0,0,0,0,0,0,0,0],[105,119,58,32,105,110,105,116,105,97,108,32,107,101,121,32,109,105,115,109,97,116,99,104,0,0,0,0,0,0,0,0],[116,114,97,110,115,102,111,114,109,32,111,114,32,110,111,32,99,111,109,112,114,101,115,115,105,111,110,58,32,99,111,109],[112,114,101,115,115,101,100,32,97,110,100,32,102,105,110,97,108,32,109,105,115,109,97,116,99,104,0,0,0,0,0,0],[117,110,115,117,112,112,111,114,116,101,100,32,111,112,101,114,97,116,105,111,110,0,0,0,0,0,0,0,0,0,0,0],[115,117,98,58,32,105,110,105,116,105,97,108,32,109,105,110,117,115,32,99,111,110,118,101,114,116,101,100,32,110,111,116],[32,101,113,117,97,108,32,116,111,32,102,105,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,100,100,58,32,105,110,105,116,105,97,108,32,112,108,117,115,32,99,111,110,118,101,114,116,101,100,32,110,111,116,32],[101,113,117,97,108,32,116,111,32,102,105,110,97,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[101,110,117,109,101,114,97,116,105,111,110,32,105,110,100,101,120,32,115,105,122,101,32,105,115,32,116,111,111,32,108,97],[114,103,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[147,237,218,30,222,226,171,166,87,171,181,200,3,117,136,80,212,87,97,62,0,250,54,95,145,189,19,44,198,68,90,138]],"0x0000000000000000000000000000000000008005":[[0,1,0,0,0,0,0,2,0,7,0,0,0,0,0,2,0,0,0,0,7,1,3,79,0,0,0,0,0,7,3,85],[0,0,0,128,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,0,1,7,0,25,0,0,0,96,1,16,2,112],[0,0,0,47,1,16,1,151,0,0,0,1,2,32,1,144,0,0,0,45,0,0,193,61,0,0,0,4,2,16,0,140],[0,0,0,92,0,0,65,61,0,0,0,0,2,7,4,59,0,0,0,224,2,32,2,112,0,0,0,49,3,32,0,156],[0,0,0,53,0,0,97,61,0,0,0,50,2,32,0,156,0,0,0,92,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,0,92,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,64,1,16,0,140],[0,0,0,92,0,0,65,61,0,0,0,4,1,112,3,112,0,0,0,0,1,1,4,59,0,0,0,51,2,16,0,156],[0,0,0,92,0,0,33,61,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,0,1,0,0,25],[0,7,0,0,0,7,3,83,0,184,0,161,0,0,4,15,0,0,0,7,2,0,3,95,0,0,0,36,2,32,3,112],[0,0,0,0,2,2,4,59,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,0,25],[0,184,0,161,0,0,4,15,0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,0,59,1,0,0,65],[0,0,0,185,0,1,4,46,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,0,92,0,0,193,61],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,48,1,0,0,65],[0,0,0,185,0,1,4,46,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,92,0,0,193,61],[0,0,0,4,2,16,0,138,0,0,0,64,2,32,0,140,0,0,0,92,0,0,65,61,0,0,0,4,2,112,3,112],[0,0,0,0,2,2,4,59,0,3,0,0,0,2,0,29,0,0,0,51,2,32,0,156,0,0,0,92,0,0,33,61],[0,0,0,36,2,112,3,112,0,0,0,0,2,2,4,59,0,0,0,52,3,32,0,156,0,0,0,92,0,0,33,61],[0,0,0,35,3,32,0,57,0,0,0,53,4,0,0,65,0,0,0,0,5,19,0,75,0,0,0,0,5,0,0,25],[0,0,0,0,5,4,128,25,0,0,0,53,3,48,1,151,0,0,0,0,6,3,0,75,0,0,0,0,4,0,128,25],[0,0,0,53,3,48,0,156,0,0,0,0,4,5,192,25,0,0,0,0,3,4,0,75,0,0,0,92,0,0,193,61],[0,0,0,4,3,32,0,57,0,0,0,0,3,55,3,79,0,0,0,0,3,3,4,59,0,2,0,0,0,3,0,29],[0,0,0,52,3,48,0,156,0,0,0,92,0,0,33,61,0,1,0,36,0,32,0,61,0,0,0,2,2,0,0,41],[0,0,0,6,2,32,2,16,0,0,0,1,2,32,0,41,0,0,0,0,1,18,0,75,0,0,0,94,0,0,161,61],[0,0,0,0,1,0,0,25,0,0,0,186,0,1,4,48,0,0,0,0,1,0,4,17,0,0,128,6,1,16,0,140],[0,0,0,149,0,0,193,61,0,0,0,2,1,0,0,107,0,0,0,147,0,0,97,61,0,0,0,47,4,0,0,65],[0,0,128,16,5,0,0,57,0,0,0,0,2,0,0,25,0,7,0,0,0,5,0,29,0,5,0,0,0,2,0,29],[0,0,0,6,1,32,2,16,0,0,0,1,1,16,0,41,0,0,0,32,2,16,0,57,0,0,0,0,2,32,3,103],[0,0,0,0,1,16,3,103,0,0,0,0,1,1,4,59,0,6,0,0,0,1,0,29,0,0,0,0,1,2,4,59],[0,4,0,0,0,1,0,29,0,0,0,3,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,0,1,0,4,20,0,0,0,47,2,16,0,156,0,0,0,0,1,4,128,25,0,0,0,192,1,16,2,16],[0,0,0,58,1,16,1,199,0,0,0,0,2,5,0,25,0,184,0,179,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,92,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,6,2,0,0,41,0,0,0,0,0,32,4,53],[0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20,0,0,0,47,2,16,0,156,0,0,0,47,1,0,128,65],[0,0,0,192,1,16,2,16,0,0,0,58,1,16,1,199,0,0,0,7,2,0,0,41,0,184,0,179,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,0,92,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,4,2,0,0,41],[0,0,0,0,0,33,4,27,0,0,0,5,2,0,0,41,0,0,0,1,2,32,0,57,0,0,0,2,1,32,0,108],[0,0,0,47,4,0,0,65,0,0,0,7,5,0,0,41,0,0,0,103,0,0,65,61,0,0,0,0,1,0,0,25],[0,0,0,185,0,1,4,46,0,0,0,54,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,45,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,55,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,56,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,57,1,0,0,65],[0,0,0,186,0,1,4,48,0,0,0,47,2,0,0,65,0,0,0,47,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,0,3,0,4,20,0,0,0,47,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,64,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,58,1,16,1,199,0,0,128,16,2,0,0,57],[0,184,0,179,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,177,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,0,186,0,1,4,48,0,0,0,182,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,0,184,0,0,4,50,0,0,0,185,0,1,4,46,0,0,0,186,0,1,4,48,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,173,126,35,46],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,49,10,176,137],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,100,101,112,108,111,121,101,114,32,115,121],[115,116,101,109,32,99,111,110,116,114,97,99,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[45,190,79,211,31,131,177,86,189,1,11,166,220,219,188,181,72,177,28,249,224,128,88,180,255,86,83,72,18,128,54,40]],"0x0000000000000000000000000000000000008002":[[0,2,0,0,0,0,0,2,0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,0,87,3,48,1,151,0,0,0,1,2,32,1,144,0,0,0,32,0,0,193,61],[0,0,0,4,2,48,0,140,0,0,0,219,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112],[0,0,0,89,5,32,0,156,0,0,0,40,0,0,33,61,0,0,0,93,4,32,0,156,0,0,0,128,0,0,97,61],[0,0,0,94,4,32,0,156,0,0,0,155,0,0,97,61,0,0,0,95,2,32,0,156,0,0,0,219,0,0,193,61],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,32,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,0,97,2,16,0,156,0,0,0,219,0,0,33,61,0,0,0,0,1,1,4,26,0,0,0,178,0,0,1,61],[0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,0,219,0,0,193,61,0,0,0,32,1,0,0,57],[0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,88,1,0,0,65,0,0,1,86,0,1,4,46],[0,0,0,90,5,32,0,156,0,0,0,181,0,0,97,61,0,0,0,91,5,32,0,156,0,0,0,209,0,0,97,61],[0,0,0,92,2,32,0,156,0,0,0,219,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,0,219,0,0,65,61],[0,0,0,96,3,0,0,65,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,97,1,16,1,151],[0,0,1,0,2,16,0,140,0,0,0,124,0,0,65,61,0,0,0,128,4,0,0,57,0,0,0,0,5,1,4,26],[0,0,0,0,2,5,0,75,0,0,0,120,0,0,193,61,0,2,0,0,0,5,0,29,0,0,0,98,2,0,0,65],[0,0,0,128,0,32,4,63,0,0,0,132,0,16,4,63,0,0,0,87,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,87,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,99,1,16,1,199],[0,0,128,3,2,0,0,57,1,85,1,80,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,87,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,0,92,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57],[0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,0,84,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,0,107,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,0,253,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,128,4,16,1,191],[0,0,0,64,0,64,4,63,0,0,0,32,1,48,0,140,0,0,0,219,0,0,65,61,0,0,0,128,1,0,4,61],[0,0,0,0,1,1,0,75,0,0,0,96,3,0,0,65,0,0,0,2,5,0,0,41,0,0,0,124,0,0,193,61],[0,0,0,100,1,80,1,151,0,0,0,96,3,0,0,65,0,0,0,101,1,16,0,156,0,0,0,0,3,5,192,25],[0,0,0,0,0,52,4,53,0,0,0,64,1,64,2,16,0,0,0,102,1,16,1,199,0,0,1,86,0,1,4,46],[0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138],[0,0,0,64,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,2,16,3,112,0,0,0,0,2,2,4,59],[0,0,0,97,3,32,0,156,0,0,0,219,0,0,33,61,0,0,0,36,1,16,3,112,0,0,0,0,1,1,4,59],[0,0,0,0,3,0,4,17,0,0,128,6,3,48,0,140,0,0,0,241,0,0,193,61,0,0,0,100,3,16,1,152],[0,0,0,238,0,0,97,61,0,0,0,106,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,43,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,110,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,111,1,0,0,65,0,0,0,250,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140],[0,0,0,219,0,0,65,61,0,0,0,4,1,16,3,112,0,0,0,0,1,1,4,59,0,0,0,97,1,16,1,151],[0,0,1,0,2,16,0,140,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57,0,0,0,0,1,1,4,26],[0,0,0,0,3,1,0,75,0,0,0,1,2,32,97,191,0,0,0,100,3,16,1,151,0,0,0,101,3,48,0,156],[0,0,0,0,3,0,0,25,0,0,0,1,3,0,96,57,0,0,0,0,2,50,1,160,0,0,0,219,1,16,2,112],[0,0,0,105,1,16,1,151,0,0,0,0,1,0,192,25,0,0,0,128,0,16,4,63,0,0,0,104,1,0,0,65],[0,0,1,86,0,1,4,46,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,2,16,3,112],[0,0,0,0,3,2,4,59,0,0,0,97,2,48,0,156,0,0,0,219,0,0,33,61,0,0,0,36,1,16,3,112],[0,0,0,0,1,1,4,59,0,2,0,0,0,1,0,29,0,0,0,0,1,0,4,17,0,0,128,6,1,16,0,140],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,0,1,0,0,0,3,0,29,1,85,1,32,0,0,4,15],[0,0,0,2,1,0,0,41,0,0,0,100,1,16,1,151,0,0,0,101,1,16,0,156,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,1,85,1,56,0,0,4,15,0,0,0,2,1,0,0,41,0,0,0,1,2,0,0,41],[0,0,0,238,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,0,219,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,0,219,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,2,1,4,59,0,0,0,97,1,32,0,156,0,0,0,221,0,0,161,61,0,0,0,0,1,0,0,25],[0,0,1,87,0,1,4,48,0,0,0,0,1,0,4,17,0,0,128,6,1,16,0,140,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,96,57,0,2,0,0,0,2,0,29,1,85,1,32,0,0,4,15,0,0,0,2,1,0,0,41],[0,0,0,0,1,1,4,26,0,1,0,0,0,1,0,29,0,0,0,100,1,16,1,151,0,0,0,101,1,16,0,156],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,96,57,1,85,1,56,0,0,4,15,0,0,0,1,1,0,0,41],[0,0,0,103,1,16,1,151,0,0,0,2,2,0,0,41,0,0,0,0,0,18,4,27,0,0,0,0,1,0,0,25],[0,0,1,86,0,1,4,46,0,0,0,106,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,45,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,107,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,108,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,109,1,0,0,65],[0,0,1,87,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,1,10,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,1,2,0,0,65,61,0,0,0,0,6,4,0,75,0,0,1,25,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,0,87,1,0,0,65,0,0,0,87,4,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16,0,0,0,0,1,33,1,159,0,0,1,87,0,1,4,48],[0,0,0,0,1,1,0,75,0,0,1,35,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,64,1,0,4,61],[0,0,0,100,2,16,0,57,0,0,0,108,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57],[0,0,0,107,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,45,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,106,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,87,2,0,0,65,0,0,0,87,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,112,1,16,1,199,0,0,1,87,0,1,4,48],[0,0,0,0,1,1,0,75,0,0,1,59,0,0,97,61,0,0,0,0,0,1,4,45,0,0,0,64,1,0,4,61],[0,0,0,100,2,16,0,57,0,0,0,113,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57],[0,0,0,114,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,46,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,106,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,87,2,0,0,65,0,0,0,87,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,0,112,1,16,1,199,0,0,1,87,0,1,4,48],[0,0,1,83,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,1,85,0,0,4,50,0,0,1,86,0,1,4,46,0,0,1,87,0,1,4,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,30,27,223],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,30,27,224],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,194,228,255,151],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,63,225,119],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,70,81,170],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,6,170,24],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,226,228,104],[197,210,70,1,134,247,35,60,146,126,125,178,220,199,3,192,229,0,182,83,202,130,39,59,123,250,216,4,93,133,164,112],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[90,169,182,181,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,128,0,0,0,0,0,0,0,0],[0,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[255,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,255,224],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,100,101,112,108,111,121,101,114,32,115,121],[115,116,101,109,32,99,111,110,116,114,97,99,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[67,111,100,101,32,104,97,115,104,32,105,115,32,110,111,116,32,102,111,114,32,97,32,99,111,110,115,116,114,117,99,116],[101,100,32,99,111,110,116,114,97,99,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[111,110,32,99,111,110,115,116,114,117,99,116,111,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,111,100,101,32,104,97,115,104,32,105,115,32,110,111,116,32,102,111,114,32,97,32,99,111,110,116,114,97,99,116,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[15,243,112,141,14,128,123,204,107,242,108,43,72,61,107,108,176,29,30,252,146,140,189,19,149,85,233,118,103,32,255,241]],"0x0000000000000000000000000000000000008008":[[0,2,0,0,0,0,0,2,0,14,0,0,0,0,0,2,0,1,0,0,0,1,3,85,0,0,0,0,3,1,0,25],[0,0,0,96,5,48,2,112,0,0,2,60,0,80,1,157,0,0,0,128,4,0,0,57,0,0,0,64,0,64,4,63],[0,0,2,60,3,80,1,151,0,0,0,1,2,32,1,144,0,0,0,49,0,0,193,61,0,0,0,4,2,48,0,140],[0,0,1,37,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,224,2,32,2,112,0,0,2,62,6,32,0,156],[0,0,0,57,0,0,33,61,0,0,2,65,4,32,0,156,0,0,0,113,0,0,97,61,0,0,2,66,2,32,0,156],[0,0,1,37,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,96,2,32,0,140,0,0,1,37,0,0,65,61,0,0,0,4,1,16,3,112],[0,0,0,0,3,1,4,59,0,0,0,0,1,3,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,192,57],[0,0,0,0,1,19,0,75,0,0,1,37,0,0,193,61,0,0,0,0,2,0,4,17,0,0,2,129,1,32,0,156],[0,0,0,236,0,0,65,61,0,0,2,87,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,52,1,0,0,57,0,0,0,164,0,16,4,63,0,0,2,131,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,2,132,1,0,0,65,0,0,0,228,0,16,4,63,0,0,2,133,1,0,0,65],[0,0,8,236,0,1,4,48,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75,0,0,1,37,0,0,193,61],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,2,61,1,0,0,65],[0,0,8,235,0,1,4,46,0,0,2,63,6,32,0,156,0,0,0,174,0,0,97,61,0,0,2,64,2,32,0,156],[0,0,1,37,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,1,37,0,0,65,61,0,0,0,4,2,16,3,112],[0,0,0,0,2,2,4,59,0,0,2,67,6,32,0,156,0,0,1,37,0,0,33,61,0,0,0,35,6,32,0,57],[0,0,2,68,7,0,0,65,0,0,0,0,8,54,0,75,0,0,0,0,8,0,0,25,0,0,0,0,8,7,128,25],[0,0,2,68,6,96,1,151,0,0,0,0,9,6,0,75,0,0,0,0,7,0,128,25,0,0,2,68,6,96,0,156],[0,0,0,0,7,8,192,25,0,0,0,0,6,7,0,75,0,0,1,37,0,0,193,61,0,0,0,4,6,32,0,57],[0,0,0,0,6,97,3,79,0,0,0,0,7,6,4,59,0,0,2,67,6,112,0,156,0,0,1,37,0,0,33,61],[0,0,0,36,8,32,0,57,0,0,0,0,2,135,0,25,0,0,0,0,3,35,0,75,0,0,1,37,0,0,65,61],[0,0,0,0,9,0,4,20,0,0,0,0,3,0,4,20,0,0,2,69,6,48,0,156,0,0,1,74,0,0,65,61],[0,0,0,68,1,64,0,57,0,0,2,89,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,1,64,0,57],[0,0,0,8,2,0,0,57,0,0,0,0,0,33,4,53,0,0,2,87,1,0,0,65,0,0,0,0,0,20,4,53],[0,0,0,4,1,64,0,57,0,0,0,32,2,0,0,57,0,0,0,0,0,33,4,53,0,0,2,60,1,0,0,65],[0,0,2,60,2,64,0,156,0,0,0,0,4,1,128,25,0,0,0,64,1,64,2,16,0,0,2,88,1,16,1,199],[0,0,8,236,0,1,4,48,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,1,37,0,0,65,61,0,0,0,0,2,0,4,17],[0,0,128,4,2,32,0,140,0,0,0,226,0,0,193,61,0,0,0,4,1,16,3,112,0,0,0,0,2,1,4,59],[0,0,0,3,1,0,0,57,0,13,0,0,0,1,0,29,0,0,0,0,1,1,4,26,0,0,0,160,0,16,4,63],[0,14,0,0,0,2,0,29,0,0,0,192,0,32,4,63,0,0,0,64,1,0,0,57,0,0,0,128,0,16,4,63],[0,0,0,224,1,0,0,57,0,0,0,64,0,16,4,63,0,0,2,60,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,2,135,1,16,1,199],[0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,37,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,13,2,0,0,41,0,0,0,0,0,18,4,27,0,0,0,0,1,0,4,19],[0,0,2,60,3,16,1,151,0,0,0,14,6,0,0,41,0,0,0,224,1,96,2,112,0,0,255,255,2,16,1,143],[0,0,0,5,1,32,2,16,0,0,0,4,4,16,1,191,0,0,0,0,81,67,0,169,0,0,0,0,84,65,0,217],[0,0,0,0,3,67,0,75,0,0,1,157,0,0,193,61,0,0,0,1,2,32,2,112,0,0,0,1,3,32,0,57],[0,0,0,7,66,48,0,201,0,0,0,7,84,32,1,26,0,0,0,0,3,67,0,75,0,0,1,157,0,0,193,61],[0,0,0,0,1,33,0,25,0,0,2,136,2,16,0,156,0,0,1,223,0,0,65,61,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,2,89,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,8,3,0,0,57,0,0,5,238,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,1,37,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,32,2,32,0,140,0,0,1,37,0,0,65,61],[0,0,0,4,2,16,3,112,0,0,0,0,2,2,4,59,0,0,2,67,4,32,0,156,0,0,1,37,0,0,33,61],[0,0,0,35,4,32,0,57,0,0,2,68,5,0,0,65,0,0,0,0,6,52,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,2,68,4,64,1,151,0,0,0,0,7,4,0,75,0,0,0,0,5,0,128,25],[0,0,2,68,4,64,0,156,0,0,0,0,5,6,192,25,0,0,0,0,4,5,0,75,0,0,1,37,0,0,193,61],[0,0,0,4,4,32,0,57,0,0,0,0,5,65,3,79,0,0,0,0,5,5,4,59,0,11,0,0,0,5,0,29],[0,0,2,67,5,80,0,156,0,0,1,37,0,0,33,61,0,0,0,36,2,32,0,57,0,10,0,0,0,2,0,29],[0,0,0,11,2,32,0,41,0,0,0,0,2,50,0,75,0,0,1,37,0,0,33,61,0,0,0,0,2,0,4,17],[0,0,128,1,2,32,0,140,0,0,1,163,0,0,193,61,0,0,0,11,2,0,0,41,0,0,0,4,2,32,0,140],[0,0,1,37,0,0,65,61,0,0,0,32,2,64,0,57,0,0,0,0,2,33,3,79,0,0,0,0,4,2,4,59],[0,0,2,92,2,64,0,156,0,0,2,155,0,0,65,61,0,0,2,87,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,2,128,1,0,0,65,0,0,0,233,0,0,1,61,0,0,2,87,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,20,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,2,134,1,0,0,65,0,0,0,196,0,16,4,63,0,0,2,91,1,0,0,65,0,0,8,236,0,1,4,48],[0,14,0,0,0,3,0,29,0,13,0,0,0,2,0,29,0,0,2,75,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,2,60,1,0,0,65,0,0,0,0,2,0,4,20,0,0,2,60,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,2,130,1,16,1,199,0,0,128,11,2,0,0,57,8,234,8,224,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,32,4,48,0,140],[0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114],[0,0,1,10,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79],[0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57,0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,103,0,75,0,0,1,2,0,0,65,61,0,0,0,0,7,5,0,75,0,0,1,25,0,0,97,61],[0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79,0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57],[0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59],[0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159],[0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144,0,0,1,39,0,0,97,61,0,0,0,31,1,64,0,57],[0,0,0,96,2,16,1,143,0,0,0,128,8,32,1,191,0,0,0,64,0,128,4,63,0,0,0,32,1,48,0,140],[0,0,0,14,5,0,0,41,0,0,1,37,0,0,65,61,0,0,0,128,1,0,4,61,0,0,255,255,3,16,0,140],[0,0,1,171,0,0,161,61,0,0,0,0,1,0,0,25,0,0,8,236,0,1,4,48,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,1,52,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,1,44,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,1,67,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,2,60,1,0,0,65],[0,0,2,60,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,8,236,0,1,4,48,0,14,0,0,0,9,0,29,0,13,0,0,0,7,0,29],[0,12,0,0,0,8,0,29,0,0,2,60,4,128,1,151,0,0,0,0,1,65,3,79,0,0,0,0,2,37,0,73],[0,0,2,60,2,32,1,151,0,0,0,0,1,33,3,223,0,0,0,192,2,48,2,16,0,0,2,70,2,32,1,151],[0,0,2,71,2,32,1,199,0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,1,234,0,0,97,61,0,0,0,63,2,48,0,57,0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61,0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114],[0,0,1,120,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59],[0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75,0,0,1,112,0,0,65,61],[0,0,0,0,5,0,0,75,0,0,1,122,0,0,97,61,0,0,0,31,5,48,1,143,0,0,0,5,3,48,2,114],[0,0,0,14,9,0,0,41,0,0,1,135,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75,0,0,1,127,0,0,65,61,0,0,0,0,6,5,0,75],[0,0,1,150,0,0,97,61,0,0,0,5,3,48,2,16,0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25],[0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51,0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137,0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53,0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140],[0,0,5,232,0,0,193,61,0,0,0,0,4,4,4,51,0,0,0,0,2,0,4,20,0,0,0,0,1,41,0,75],[0,0,3,173,0,0,129,61,0,0,2,126,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,0,4,0,16,4,63,0,0,2,127,1,0,0,65,0,0,8,236,0,1,4,48,0,0,2,87,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,31,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,2,90,1,0,0,65,0,0,0,233,0,0,1,61,0,0,1,64,3,32,0,57],[0,0,0,64,0,48,4,63,0,0,0,0,0,8,4,53,0,0,0,160,3,32,0,57,0,11,0,0,0,3,0,29],[0,0,0,0,0,83,4,53,0,0,2,79,4,0,0,65,0,0,0,0,3,5,0,75,0,0,0,0,4,0,96,25],[0,0,0,224,3,32,0,57,0,14,0,0,0,3,0,29,0,0,0,13,9,0,0,41,0,0,0,0,0,147,4,53],[0,0,0,192,3,32,0,57,0,9,0,0,0,3,0,29,0,0,0,0,0,19,4,53,0,0,0,1,3,0,3,103],[0,0,0,36,5,48,3,112,0,0,0,0,5,5,4,59,0,0,1,32,7,32,0,57,0,0,1,0,2,32,1,191],[0,10,0,0,0,2,0,29,0,0,0,0,0,82,4,53,0,0,0,68,2,48,3,112,0,0,0,0,6,2,4,59],[0,12,0,0,0,7,0,29,0,0,0,0,0,103,4,53,0,0,0,0,2,8,4,51,0,0,0,248,7,32,2,16],[0,0,0,64,2,0,4,61,0,0,0,32,3,32,0,57,0,0,0,0,0,115,4,53,0,0,0,33,7,32,0,57],[0,0,0,0,0,71,4,53,0,0,0,240,1,16,2,16,0,0,0,34,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,0,96,1,144,2,16,0,0,0,36,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,88,1,32,0,57],[0,0,0,0,0,97,4,53,0,0,0,56,1,32,0,57,0,0,0,0,0,81,4,53,0,0,0,88,1,0,0,57],[0,0,0,0,0,18,4,53,0,0,2,80,1,32,0,156,0,0,2,5,0,0,161,61,0,0,2,126,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,1,160,0,0,1,61,0,0,0,40,1,16,0,57],[0,0,0,0,2,16,4,32,0,0,0,64,1,0,4,61,0,0,0,0,2,2,0,75,0,0,2,136,0,0,193,61],[0,0,0,68,2,16,0,57,0,0,2,86,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,20,3,0,0,57,0,0,5,238,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,1,245,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,1,238,0,0,65,61,0,0,0,0,5,4,0,75,0,0,2,3,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,8,236,0,1,4,48,0,0,0,128,1,32,0,57,0,0,0,64,0,16,4,63,0,0,2,60,1,0,0,65],[0,0,2,60,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,64,3,48,2,16,0,0,0,0,2,2,4,51],[0,0,2,60,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159],[0,0,0,0,3,0,4,20,0,0,2,60,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16],[0,0,0,0,1,33,1,159,0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,0,13,0,0,0,8,0,29],[8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,37,0,0,97,61,0,0,0,0,2,1,4,59],[0,0,0,64,1,0,4,61,0,0,0,64,3,16,0,57,0,0,0,0,4,0,4,26,0,0,0,0,0,35,4,53],[0,0,0,32,2,16,0,57,0,0,0,0,0,66,4,53,0,0,0,64,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61,0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,2,60,3,0,0,65,0,0,2,60,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,2,60,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,2,60,4,32,0,156,0,0,0,0,2,3,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57],[8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,1,37,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,0,0,16,4,27,0,0,0,1,3,0,0,57,0,0,0,0,2,3,4,26,0,0,0,1,1,0,0,138],[0,8,0,0,0,2,0,29,0,0,0,0,1,18,0,75,0,0,1,157,0,0,97,61,0,0,0,8,1,0,0,41],[0,0,0,1,1,16,0,57,0,0,0,0,0,19,4,27,0,0,0,13,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,0,255,1,16,1,143,0,0,0,64,2,0,4,61,0,0,0,0,1,18,4,54,0,0,0,11,4,0,0,41],[0,0,0,0,4,4,4,51,0,0,0,0,4,4,0,75,0,0,0,0,4,0,0,25,0,0,0,1,4,0,192,57],[0,0,0,0,0,65,4,53,0,0,0,9,1,0,0,41,0,0,0,0,1,1,4,51,0,0,255,255,1,16,1,143],[0,0,0,64,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,14,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,2,78,1,16,1,151,0,0,0,96,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,10,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,128,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,12,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,160,4,32,0,57,0,0,0,0,0,20,4,53,0,0,2,60,5,0,0,65],[0,0,2,60,1,32,0,156,0,0,0,0,2,5,128,25,0,0,0,0,1,0,4,20,0,0,2,60,4,16,0,156],[0,0,0,0,1,5,128,25,0,0,0,64,2,32,2,16,0,0,0,192,1,16,2,16,0,0,0,0,1,33,1,159],[0,0,2,81,1,16,1,199,0,0,128,13,2,0,0,57,0,0,2,82,4,0,0,65,8,234,8,219,0,0,4,15],[0,0,0,1,1,32,1,144,0,0,1,37,0,0,97,61,0,0,0,120,1,0,0,57,0,0,0,0,3,16,4,32],[0,0,0,64,1,0,4,61,0,0,2,60,2,16,0,156,0,0,2,60,2,0,0,65,0,0,0,0,2,1,64,25],[0,0,0,64,2,32,2,16,0,0,0,0,3,3,0,75,0,0,5,2,0,0,193,61,0,0,0,68,3,16,0,57],[0,0,2,86,4,0,0,65,0,0,0,0,0,67,4,53,0,0,0,36,3,16,0,57,0,0,0,20,4,0,0,57],[0,0,0,0,0,67,4,53,0,0,2,87,3,0,0,65,0,0,0,0,0,49,4,53,0,0,0,4,1,16,0,57],[0,0,0,32,3,0,0,57,0,0,0,0,0,49,4,53,0,0,2,88,1,32,1,199,0,0,8,236,0,1,4,48],[0,0,0,0,0,97,4,53,0,0,2,60,2,0,0,65,0,0,0,0,3,0,4,20,0,0,2,60,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,2,60,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,2,137,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,1,3,0,0,57,0,0,2,138,4,0,0,65,8,234,8,219,0,0,4,15,0,0,0,1,1,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,1,0,0,25,0,0,8,235,0,1,4,46,0,0,0,0,1,49,3,79],[0,6,0,0,0,4,0,29,0,0,0,224,6,64,2,112,0,0,2,93,2,0,0,65,0,0,0,64,0,32,4,63],[0,0,8,0,2,0,0,57,0,7,0,0,0,2,0,29,0,0,0,128,0,32,4,63,0,0,0,160,2,0,0,57],[0,0,0,0,3,0,0,25,0,0,0,5,4,48,2,16,0,0,0,0,4,65,3,79,0,0,0,0,4,4,4,59],[0,0,0,0,2,66,4,54,0,0,0,1,3,48,0,57,0,0,8,0,4,48,0,140,0,0,2,165,0,0,65,61],[0,0,0,4,2,0,0,57,0,0,0,6,1,0,0,41,0,0,2,71,1,16,0,156,0,0,0,0,8,0,0,25],[0,0,3,10,0,0,129,61,0,0,0,0,1,0,4,26,0,0,0,0,1,24,0,75,0,0,3,152,0,0,193,61],[0,13,0,0,0,2,0,29,0,0,0,6,1,0,0,41,0,0,2,97,1,16,0,156,0,0,2,194,0,0,33,61],[0,0,2,98,1,0,0,65,0,0,0,128,2,0,4,61,0,0,0,0,2,98,0,75,0,0,3,6,0,0,161,61],[0,0,0,5,2,96,2,16,0,0,0,160,2,32,0,57,0,0,0,0,0,18,4,53,0,0,7,255,2,96,0,140],[0,0,0,1,6,96,0,57,0,0,2,185,0,0,65,61,0,9,0,64,0,0,0,61,0,8,128,16,0,0,0,61],[0,0,0,7,1,0,0,41,0,6,0,0,0,1,0,29,0,7,0,1,0,16,2,120,0,0,0,0,4,0,0,25],[0,0,0,1,1,64,2,16,0,0,0,128,2,0,4,61,0,0,0,0,3,18,0,75,0,0,3,6,0,0,161,61],[0,0,0,1,1,16,1,191,0,0,0,0,2,18,0,75,0,0,3,6,0,0,161,61,0,0,0,5,1,16,2,16],[0,0,0,160,1,16,0,57,0,0,0,0,2,1,4,51,0,14,0,0,0,4,0,29,0,0,0,6,1,64,2,16],[0,0,0,160,1,16,0,57,0,12,0,0,0,1,0,29,0,0,0,0,3,1,4,51,0,0,0,64,1,0,4,61],[0,0,0,64,4,16,0,57,0,0,0,0,0,36,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,0,8,2,0,0,41,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,128,2,0,4,61,0,0,0,14,4,0,0,41,0,0,0,0,2,66,0,75],[0,0,3,6,0,0,161,61,0,0,0,5,2,64,2,16,0,0,0,12,2,32,0,105,0,0,0,0,1,1,4,59],[0,0,0,0,0,18,4,53,0,0,0,1,4,64,0,57,0,0,0,7,1,64,0,108,0,0,2,200,0,0,65,61],[0,0,0,6,1,0,0,41,0,0,0,3,1,16,0,140,0,0,2,196,0,0,33,61,0,0,0,128,1,0,4,61],[0,0,0,0,1,1,0,75,0,0,5,6,0,0,193,61,0,0,2,126,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,50,1,0,0,57,0,0,1,160,0,0,1,61,0,0,0,4,1,0,0,57,0,9,0,89,0,0,0,146],[0,0,0,0,7,0,0,25,0,0,0,0,8,0,0,25,0,8,0,0,0,6,0,29,0,0,0,88,3,16,0,57],[0,13,0,0,0,3,0,29,0,0,0,11,2,48,0,108,0,0,1,37,0,0,33,61,0,0,0,10,2,16,0,41],[0,0,0,0,1,0,4,20,0,0,2,60,3,32,1,151,0,0,0,9,4,32,0,108,0,0,1,157,0,0,33,61],[0,0,0,88,2,32,0,57,0,0,0,0,4,0,0,49,0,0,0,0,5,36,0,75,0,0,1,157,0,0,65,61],[0,12,0,0,0,8,0,29,0,14,0,0,0,7,0,29,0,0,0,1,3,48,3,103,0,0,2,60,5,16,0,156],[0,0,0,167,0,0,33,61,0,0,0,0,2,36,0,73,0,0,2,60,2,32,1,151,0,0,0,0,2,35,3,223],[0,0,0,192,1,16,2,16,0,0,2,70,1,16,1,151,0,0,2,71,1,16,1,199,0,0,0,0,1,18,3,175],[0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144,0,0,4,202,0,0,97,61,0,0,0,63,2,48,0,57],[0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75],[0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61],[0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54],[0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114,0,0,3,74,0,0,97,61,0,0,0,0,6,0,0,49],[0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25],[0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,87,0,75,0,0,3,66,0,0,65,61,0,0,0,0,5,0,0,75,0,0,3,76,0,0,97,61],[0,0,0,5,5,48,2,114,0,0,3,87,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,3,79,0,0,65,61,0,0,0,31,3,48,1,144],[0,0,3,102,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25],[0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140],[0,0,0,14,3,0,0,41,0,0,0,12,5,0,0,41,0,0,5,232,0,0,193,61,0,0,0,128,1,0,4,61],[0,0,0,0,1,49,0,75,0,0,3,6,0,0,161,61,0,0,0,0,2,4,4,51,0,0,0,5,1,48,2,16],[0,0,0,160,1,16,0,57,0,0,0,0,0,33,4,53,0,0,0,64,1,0,4,61,0,0,0,64,3,16,0,57],[0,0,0,0,0,35,4,53,0,0,0,64,2,0,0,57,0,0,0,0,2,33,4,54,0,0,0,0,0,82,4,53],[0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61,0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63],[0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65,0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16],[0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156,0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57],[8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144,0,0,0,8,6,0,0,41,0,0,0,14,7,0,0,41],[0,0,1,37,0,0,97,61,0,0,0,0,8,1,4,59,0,0,0,1,7,112,0,57,0,0,0,0,1,103,0,75],[0,0,0,13,2,0,0,41,0,0,0,0,1,2,0,25,0,0,3,15,0,0,65,61,0,0,2,177,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,2,94,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,2,95,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,60,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65,0,0,0,0,0,33,4,53],[0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,60,2,0,0,65],[0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16,0,0,2,96,1,16,1,199],[0,0,8,236,0,1,4,48,0,8,0,0,0,2,0,29,0,0,0,2,1,0,0,57,0,11,0,0,0,1,0,29],[0,0,0,0,3,1,4,26,0,0,0,64,1,0,4,61,0,0,0,64,2,16,0,57,0,10,0,0,0,4,0,29],[0,0,0,0,0,66,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,50,4,53,0,0,0,64,3,0,0,57],[0,9,0,0,0,3,0,29,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,4,0,0,65,0,0,2,60,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,11,2,0,0,41,0,0,0,0,0,18,4,27],[0,0,2,75,1,0,0,65,0,0,0,64,4,0,4,61,0,11,0,0,0,4,0,29,0,0,0,0,0,20,4,53],[0,0,0,0,1,0,4,20,0,0,2,60,2,16,0,156,0,0,2,60,3,0,0,65,0,0,0,0,1,3,128,25],[0,0,2,60,2,64,0,156,0,0,0,0,3,4,64,25,0,0,0,64,2,48,2,16,0,0,0,192,1,16,2,16],[0,0,0,0,1,33,1,159,0,0,2,76,1,16,1,199,0,0,128,11,2,0,0,57,8,234,8,224,0,0,4,15],[0,0,0,11,10,0,0,41,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151],[0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143],[0,0,0,5,6,64,2,114,0,0,3,247,0,0,97,61,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,138,0,25,0,0,0,0,8,129,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,3,239,0,0,65,61,0,0,0,0,9,10,0,25],[0,0,0,0,7,5,0,75,0,0,4,7,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,6,105,0,25,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,4,229,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,1,16,1,143,0,0,0,0,2,145,0,25],[0,0,0,0,1,18,0,75,0,0,0,0,1,0,0,25,0,0,0,1,1,0,64,57,0,7,0,0,0,2,0,29],[0,0,2,67,2,32,0,156,0,0,1,219,0,0,33,61,0,0,0,1,1,16,1,144,0,0,1,219,0,0,193,61],[0,0,0,7,1,0,0,41,0,0,0,64,0,16,4,63,0,0,0,32,1,48,0,140,0,0,1,37,0,0,65,61],[0,0,0,0,1,9,4,51,0,0,255,255,2,16,0,140,0,0,1,37,0,0,33,61,0,0,0,7,2,0,0,41],[0,0,2,77,2,32,0,156,0,0,1,219,0,0,33,61,0,0,0,7,3,0,0,41,0,0,0,192,2,48,0,57],[0,0,0,64,0,32,4,63,0,0,0,0,4,0,4,16,0,0,2,78,2,64,1,151,0,0,0,96,5,48,0,57],[0,5,0,0,0,5,0,29,0,0,0,0,0,37,4,53,0,0,0,32,5,48,0,57,0,0,0,1,2,0,0,57],[0,11,0,0,0,2,0,29,0,3,0,0,0,5,0,29,0,0,0,0,0,37,4,53,0,0,0,160,2,48,0,57],[0,0,0,10,7,0,0,41,0,6,0,0,0,2,0,29,0,0,0,0,0,114,4,53,0,0,0,128,2,48,0,57],[0,0,0,0,8,0,4,17,0,4,0,0,0,2,0,29,0,0,0,0,0,130,4,53,0,0,0,0,0,3,4,53],[0,0,0,64,2,48,0,57,0,2,0,0,0,2,0,29,0,0,0,0,0,18,4,53,0,0,0,64,2,0,4,61],[0,0,0,32,3,32,0,57,0,0,0,0,0,3,4,53,0,0,0,33,5,32,0,57,0,0,2,79,6,0,0,65],[0,0,0,0,0,101,4,53,0,0,0,240,1,16,2,16,0,0,0,34,5,32,0,57,0,0,0,0,0,21,4,53],[0,0,0,96,1,64,2,16,0,0,0,36,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,88,1,32,0,57],[0,0,0,0,0,113,4,53,0,0,0,88,1,0,0,57,0,0,0,0,0,18,4,53,0,0,0,56,1,32,0,57],[0,1,0,0,0,8,0,29,0,0,0,0,0,129,4,53,0,0,2,80,1,32,0,156,0,0,1,219,0,0,33,61],[0,0,0,128,1,32,0,57,0,0,0,64,0,16,4,63,0,0,2,60,1,0,0,65,0,0,2,60,4,48,0,156],[0,0,0,0,3,1,128,25,0,0,0,64,3,48,2,16,0,0,0,0,2,2,4,51,0,0,2,60,4,32,0,156],[0,0,0,0,2,1,128,25,0,0,0,96,2,32,2,16,0,0,0,0,2,50,1,159,0,0,0,0,3,0,4,20],[0,0,2,60,4,48,0,156,0,0,0,0,3,1,128,25,0,0,0,192,1,48,2,16,0,0,0,0,1,33,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,2,1,4,59,0,0,0,64,1,0,4,61,0,0,0,64,3,16,0,57],[0,0,0,0,4,0,4,26,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,66,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,0,0,65,0,0,2,60,4,32,0,156],[0,0,0,0,2,3,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,4,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,4,32,0,156,0,0,0,0,2,3,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,1,37,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,16,4,27,0,0,0,11,1,0,0,41],[0,0,0,0,1,1,4,26,0,0,0,1,2,0,0,138,0,0,0,0,2,33,0,75,0,0,1,157,0,0,97,61],[0,0,0,1,1,16,0,57,0,0,0,11,3,0,0,41,0,0,0,0,0,19,4,27,0,0,0,7,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,0,255,1,16,1,143,0,0,0,64,2,0,4,61,0,0,0,0,1,18,4,54],[0,0,0,3,4,0,0,41,0,0,0,0,4,4,4,51,0,0,0,0,4,4,0,75,0,0,0,0,4,0,0,25],[0,0,0,1,4,0,192,57,0,0,0,0,0,65,4,53,0,0,0,2,1,0,0,41,0,0,0,0,1,1,4,51],[0,0,255,255,1,16,1,143,0,0,0,64,4,32,0,57,0,0,0,0,0,20,4,53,0,0,0,5,1,0,0,41],[0,0,0,0,1,1,4,51,0,0,2,78,1,16,1,151,0,0,0,96,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,0,4,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,128,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,0,6,1,0,0,41,0,0,0,0,1,1,4,51,0,0,0,160,4,32,0,57,0,0,0,0,0,20,4,53],[0,0,2,60,1,0,0,65,0,0,2,60,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,0,5,0,4,20],[0,0,2,60,4,80,0,156,0,0,0,0,5,1,128,25,0,0,0,64,1,32,2,16,0,0,0,192,2,80,2,16],[0,0,0,0,1,18,1,159,0,0,2,81,1,16,1,199,0,0,128,13,2,0,0,57,0,0,2,82,4,0,0,65],[8,234,8,219,0,0,4,15,0,0,0,1,1,32,1,144,0,0,0,13,1,0,0,41,0,0,1,37,0,0,97,61],[0,0,0,92,2,16,0,57,0,0,0,0,1,0,4,19,0,0,2,60,3,16,1,151,0,0,0,0,65,35,0,169],[0,0,2,83,2,32,1,151,0,0,2,83,4,16,1,151,0,0,0,0,66,36,0,217,0,0,0,0,2,35,0,75],[0,0,0,8,3,0,0,41,0,0,1,157,0,0,193,61,0,0,0,14,2,48,0,105,0,0,0,160,1,16,0,57],[0,0,0,0,1,33,0,26,0,0,1,157,0,0,65,61,0,0,2,69,2,16,0,156,0,0,6,200,0,0,65,61],[0,0,0,64,4,0,4,61,0,0,0,96,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,4,213,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,4,206,0,0,65,61,0,0,0,0,5,4,0,75,0,0,4,227,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,8,236,0,1,4,48,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114],[0,0,4,242,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25],[0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,86,0,75,0,0,4,234,0,0,65,61,0,0,0,0,6,4,0,75,0,0,5,1,0,0,97,61],[0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159],[0,0,0,0,0,21,4,53,0,0,1,67,0,0,1,61,0,0,0,8,3,0,0,41,0,0,0,0,0,49,4,53],[0,0,2,85,1,32,1,199,0,0,8,235,0,1,4,46,0,0,0,5,1,0,0,138,0,8,0,0,0,1,0,29],[0,0,0,13,1,16,0,107,0,0,1,157,0,0,33,61,0,0,0,13,1,0,0,41,0,0,0,4,3,16,0,57],[0,0,0,11,1,48,0,108,0,0,1,37,0,0,33,61,0,0,0,160,1,0,4,61,0,5,0,0,0,1,0,29],[0,0,0,13,2,0,0,41,0,0,0,10,1,32,0,41,0,0,0,1,1,16,3,103,0,0,0,0,1,1,4,59],[0,0,2,71,2,16,0,156,0,0,0,0,9,0,0,25,0,0,5,90,0,0,129,61,0,0,0,2,1,0,0,57],[0,4,0,0,0,1,0,29,0,0,0,0,1,1,4,26,0,0,0,0,1,25,0,75,0,0,5,250,0,0,193,61],[0,0,0,0,2,3,0,25,0,0,0,8,1,32,0,108,0,0,1,157,0,0,33,61,0,0,0,4,3,32,0,57],[0,0,0,11,1,48,0,108,0,0,1,37,0,0,33,61,0,0,0,10,1,32,0,41,0,0,0,1,1,16,3,103],[0,0,0,0,1,1,4,59,0,0,2,71,2,16,0,156,0,0,0,0,9,0,0,25,0,0,6,45,0,0,129,61],[0,0,0,0,5,3,0,25,0,0,0,3,1,0,0,57,0,13,0,0,0,1,0,29,0,0,0,0,1,1,4,26],[0,0,0,0,1,25,0,75,0,0,6,205,0,0,193,61,0,0,0,11,1,80,0,108,0,0,3,6,0,0,129,61],[0,0,0,10,1,80,0,41,0,0,0,1,2,0,3,103,0,0,0,0,3,18,3,79,0,0,0,0,3,3,4,59],[0,0,2,116,3,48,1,151,0,0,2,79,3,48,0,156,0,0,7,32,0,0,193,61,0,0,0,0,4,5,0,25],[0,0,0,8,3,64,0,108,0,0,1,157,0,0,33,61,0,0,0,4,3,64,0,57,0,0,0,11,4,48,0,108],[0,0,1,37,0,0,33,61,0,0,0,1,1,16,0,57,0,0,0,0,1,18,3,79,0,0,0,0,1,1,4,59],[0,0,0,11,4,48,0,108,0,0,3,6,0,0,129,61,0,0,0,232,1,16,2,112,0,0,0,10,3,48,0,41],[0,0,0,0,4,50,3,79,0,0,0,5,3,80,0,57,0,12,0,0,0,49,0,30,0,0,0,0,5,4,4,59],[0,0,1,157,0,0,65,61,0,0,0,12,6,0,0,41,0,0,0,11,4,96,0,108,0,0,1,37,0,0,33,61],[0,0,0,12,4,0,0,41,0,0,2,119,4,64,0,156,0,0,7,90,0,0,65,61,0,0,0,64,1,0,4,61],[0,0,0,68,2,16,0,57,0,0,2,125,3,0,0,65,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,36,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,4,2,16,0,57,0,0,5,243,0,0,1,61,0,7,0,224,0,16,2,120,0,0,0,0,8,0,0,25],[0,0,0,0,9,0,0,25,0,0,0,8,1,48,0,108,0,0,1,157,0,0,33,61,0,0,0,4,2,48,0,57],[0,0,0,11,1,32,0,108,0,0,1,37,0,0,33,61,0,0,0,10,3,48,0,41,0,0,0,1,1,0,3,103],[0,0,0,0,3,49,3,79,0,0,0,0,3,3,4,59,0,0,0,224,3,48,2,112,0,0,0,0,7,35,0,26],[0,0,1,157,0,0,65,61,0,0,0,11,4,112,0,108,0,0,1,37,0,0,33,61,0,0,0,10,2,32,0,41],[0,0,0,0,3,35,0,26,0,0,2,60,4,32,1,151,0,0,0,0,2,0,4,20,0,0,1,157,0,0,65,61],[0,0,0,0,5,0,0,49,0,0,0,0,6,53,0,75,0,0,1,157,0,0,65,61,0,14,0,0,0,9,0,29],[0,12,0,0,0,8,0,29,0,13,0,0,0,7,0,29,0,0,2,60,6,32,0,156,0,0,0,167,0,0,33,61],[0,0,0,0,1,65,3,79,0,0,0,0,3,53,0,73,0,0,2,60,3,48,1,151,0,0,0,0,1,49,3,223],[0,0,0,192,2,32,2,16,0,0,2,70,2,32,1,151,0,0,2,71,2,32,1,199,0,0,0,0,1,33,3,175],[0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144,0,0,6,18,0,0,97,61,0,0,0,63,2,48,0,57],[0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75],[0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61],[0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61,0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54],[0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114,0,0,5,162,0,0,97,61,0,0,0,0,6,0,0,49],[0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25],[0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57],[0,0,0,0,8,87,0,75,0,0,5,154,0,0,65,61,0,0,0,0,5,0,0,75,0,0,5,164,0,0,97,61],[0,0,0,5,5,48,2,114,0,0,0,14,9,0,0,41,0,0,5,176,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,5,168,0,0,65,61],[0,0,0,31,3,48,1,144,0,0,5,191,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,84,0,25,0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,54,1,207],[0,0,0,0,6,54,2,47,0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47],[0,0,0,0,1,49,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,0,1,2,4,51],[0,0,0,32,1,16,0,140,0,0,5,232,0,0,193,61,0,0,0,0,2,4,4,51,0,0,0,64,1,0,4,61],[0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,13,3,0,0,41,0,0,0,12,8,0,0,41,0,0,1,37,0,0,97,61,0,0,0,0,9,1,4,59],[0,0,0,1,8,128,0,57,0,0,0,7,1,128,0,108,0,0,5,93,0,0,65,61,0,0,5,23,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,2,99,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,2,60,2,0,0,65,0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,2,88,1,16,1,199,0,0,8,236,0,1,4,48,0,0,0,64,1,0,4,61,0,0,0,132,2,16,0,57],[0,0,2,100,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,100,2,16,0,57,0,0,2,101,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,2,102,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,68,3,0,0,57,0,0,0,0,0,50,4,53,0,0,2,87,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,2,60,2,0,0,65,0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,2,103,1,16,1,199,0,0,8,236,0,1,4,48,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114],[0,0,6,29,0,0,97,61,0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75],[0,0,6,22,0,0,65,61,0,0,0,0,5,4,0,75,0,0,6,43,0,0,97,61,0,0,0,3,4,64,2,16],[0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47],[0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16],[0,0,8,236,0,1,4,48,0,6,0,224,0,16,2,120,0,0,0,0,8,0,0,25,0,0,0,0,9,0,0,25],[0,0,0,8,1,48,0,108,0,0,1,157,0,0,33,61,0,0,0,4,2,48,0,57,0,0,0,11,1,32,0,108],[0,0,1,37,0,0,33,61,0,0,0,10,3,48,0,41,0,0,0,1,1,0,3,103,0,0,0,0,3,49,3,79],[0,0,0,0,3,3,4,59,0,0,0,224,10,48,2,112,0,0,0,0,7,42,0,26,0,0,1,157,0,0,65,61],[0,0,0,11,4,112,0,108,0,0,1,37,0,0,33,61,0,0,2,104,4,48,1,152,0,0,7,42,0,0,193,61],[0,0,2,106,4,48,0,156,0,0,7,46,0,0,129,61,0,0,2,107,3,48,1,152,0,0,7,50,0,0,97,61],[0,0,0,10,2,32,0,41,0,0,0,0,3,42,0,26,0,0,2,60,4,32,1,151,0,0,0,0,2,0,4,20],[0,0,1,157,0,0,65,61,0,0,0,0,5,0,0,49,0,0,0,0,6,53,0,75,0,0,1,157,0,0,65,61],[0,13,0,0,0,10,0,29,0,14,0,0,0,9,0,29,0,7,0,0,0,8,0,29,0,12,0,0,0,7,0,29],[0,0,2,60,6,32,0,156,0,0,0,167,0,0,33,61,0,0,0,0,1,65,3,79,0,0,0,0,3,53,0,73],[0,0,2,60,3,48,1,151,0,0,0,0,1,49,3,223,0,0,0,192,2,32,2,16,0,0,2,70,2,32,1,151],[0,0,2,71,2,32,1,199,0,0,0,0,1,33,3,175,0,0,0,2,2,0,0,57,8,234,8,229,0,0,4,15],[0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144],[0,0,7,57,0,0,97,61,0,0,0,63,2,48,0,57,0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,4,66,0,25,0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57],[0,0,2,67,6,64,0,156,0,0,1,219,0,0,33,61,0,0,0,1,5,80,1,144,0,0,1,219,0,0,193,61],[0,0,0,64,0,64,4,63,0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114],[0,0,0,13,10,0,0,41,0,0,6,125,0,0,97,61,0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75],[0,0,6,117,0,0,65,61,0,0,0,0,5,0,0,75,0,0,6,127,0,0,97,61,0,0,0,5,5,48,2,114],[0,0,0,14,9,0,0,41,0,0,6,139,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,6,131,0,0,65,61,0,0,0,31,3,48,1,144],[0,0,6,154,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,84,0,25],[0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,3,48,0,137,0,0,0,0,1,49,2,47,0,0,0,0,1,49,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,64,1,0,4,61,0,0,0,0,2,2,4,51],[0,0,0,32,2,32,0,140,0,0,7,84,0,0,193,61,0,0,0,0,2,4,4,51,0,0,2,109,2,32,1,151],[0,0,0,219,3,160,2,16,0,0,2,110,3,48,1,151,0,0,0,0,2,35,1,159,0,0,2,79,2,32,1,199],[0,0,0,64,3,16,0,57,0,0,0,0,0,35,4,53,0,0,0,32,2,16,0,57,0,0,0,0,0,146,4,53],[0,0,0,9,3,0,0,41,0,0,0,0,0,49,4,53,0,0,2,73,3,16,0,156,0,0,1,219,0,0,33,61],[0,0,0,96,3,16,0,57,0,0,0,64,0,48,4,63,0,0,2,60,3,32,0,156,0,0,2,60,4,0,0,65],[0,0,0,0,2,4,128,25,0,0,0,64,2,32,2,16,0,0,0,0,1,1,4,51,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20],[0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159],[0,0,2,74,1,16,1,199,0,0,128,16,2,0,0,57,8,234,8,224,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,12,3,0,0,41,0,0,0,7,8,0,0,41,0,0,1,37,0,0,97,61,0,0,0,0,9,1,4,59],[0,0,0,1,8,128,0,57,0,0,0,6,1,128,0,108,0,0,6,48,0,0,65,61,0,0,5,40,0,0,1,61],[0,0,0,0,2,16,4,32,0,0,0,64,1,0,4,61,0,0,0,0,2,2,0,75,0,0,6,218,0,0,193,61],[0,0,1,228,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,132,2,16,0,57,0,0,2,113,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,100,2,16,0,57,0,0,2,114,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,2,115,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,94,3,0,0,57,0,0,6,6,0,0,1,61,0,0,0,32,2,0,0,57,0,0,0,0,2,33,4,54],[0,0,0,13,5,0,0,41,0,0,0,0,0,82,4,53,0,0,0,31,3,80,1,143,0,0,0,64,2,16,0,57],[0,0,0,12,4,0,0,41,0,0,0,1,4,64,3,103,0,0,0,5,5,80,2,114,0,0,6,237,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,116,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,6,229,0,0,65,61,0,0,0,0,6,3,0,75,0,0,6,252,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,4,84,3,79,0,0,0,0,5,82,0,25,0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47,0,0,0,0,4,4,4,59,0,0,1,0,3,48,0,137],[0,0,0,0,4,52,2,47,0,0,0,0,3,52,1,207,0,0,0,0,3,99,1,159,0,0,0,0,0,53,4,53],[0,0,0,13,3,0,0,41,0,0,0,0,2,50,0,25,0,0,0,0,0,2,4,53,0,0,0,95,2,48,0,57],[0,0,0,32,3,0,0,138,0,0,0,0,2,50,1,111,0,0,2,60,4,0,0,65,0,0,2,60,3,16,0,156],[0,0,0,0,1,4,128,25,0,0,0,64,1,16,2,16,0,0,2,60,3,32,0,156,0,0,0,0,2,4,128,25],[0,0,0,96,2,32,2,16,0,0,0,0,1,33,1,159,0,0,0,0,2,0,4,20,0,0,2,60,3,32,0,156],[0,0,0,0,2,4,128,25,0,0,0,192,2,32,2,16,0,0,0,0,1,18,1,159,0,0,2,74,1,16,1,199],[0,0,128,13,2,0,0,57,0,0,0,3,3,0,0,57,0,0,2,84,4,0,0,65,0,0,0,1,5,0,0,41],[0,0,0,10,6,0,0,41,8,234,8,219,0,0,4,15,0,0,0,1,1,32,1,144,0,0,1,37,0,0,97,61],[0,0,0,64,1,0,4,61,0,0,0,10,2,0,0,41,0,0,0,0,0,33,4,53,0,0,2,60,2,16,0,156],[0,0,2,60,1,0,128,65,0,0,0,64,1,16,2,16,0,0,2,85,1,16,1,199,0,0,8,235,0,1,4,46],[0,0,0,64,1,0,4,61,0,0,0,100,2,16,0,57,0,0,2,117,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,68,2,16,0,57,0,0,2,118,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,39,3,0,0,57,0,0,3,161,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,2,105,3,0,0,65,0,0,7,53,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,2,112,3,0,0,65,0,0,7,53,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,2,111,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,4,3,0,0,41],[0,0,5,238,0,0,1,61,0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,7,68,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,118,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,7,61,0,0,65,61],[0,0,0,0,5,4,0,75,0,0,7,82,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16],[0,0,0,0,5,2,4,51,0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,81,1,159,0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,8,236,0,1,4,48],[0,0,0,68,2,16,0,57,0,0,2,108,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57],[0,0,0,25,3,0,0,57,0,0,5,238,0,0,1,61,0,0,0,12,4,0,0,41,0,0,0,4,6,64,0,57],[0,0,0,11,4,96,0,108,0,0,1,37,0,0,33,61,0,0,0,12,7,0,0,41,0,0,0,10,4,112,0,41],[0,0,0,0,4,66,3,79,0,0,0,0,8,4,4,59,0,0,0,224,7,128,2,112,0,0,1,16,148,112,0,201],[0,0,2,71,8,128,0,156,0,0,7,105,0,0,65,61,0,0,0,0,152,116,0,217,0,0,1,16,8,128,0,140],[0,0,1,157,0,0,193,61,0,0,0,0,9,100,0,25,0,9,0,0,0,9,0,29,0,0,0,11,8,144,0,108],[0,0,1,37,0,0,33,61,0,0,0,248,5,80,2,112,0,0,0,64,10,0,4,61,0,0,0,68,8,160,0,57],[0,0,0,128,9,0,0,57,0,0,0,0,0,152,4,53,0,0,0,36,8,160,0,57,0,0,0,0,0,88,4,53],[0,0,2,120,5,0,0,65,0,0,0,0,0,90,4,53,0,0,0,10,6,96,0,41,0,0,0,132,5,160,0,57],[0,0,0,0,0,69,4,53,0,0,0,4,5,160,0,57,0,0,0,0,0,117,4,53,0,0,0,0,8,98,3,79],[0,0,0,31,7,64,1,143,0,14,0,0,0,10,0,29,0,0,0,164,6,160,0,57,0,0,0,5,9,64,2,114],[0,0,7,138,0,0,97,61,0,0,0,0,10,0,0,25,0,0,0,5,11,160,2,16,0,0,0,0,12,182,0,25],[0,0,0,0,11,184,3,79,0,0,0,0,11,11,4,59,0,0,0,0,0,188,4,53,0,0,0,1,10,160,0,57],[0,0,0,0,11,154,0,75,0,0,7,130,0,0,65,61,0,0,0,10,3,48,0,41,0,0,0,0,10,7,0,75],[0,0,7,154,0,0,97,61,0,0,0,5,9,144,2,16,0,0,0,0,8,152,3,79,0,0,0,0,9,150,0,25],[0,0,0,3,7,112,2,16,0,0,0,0,10,9,4,51,0,0,0,0,10,122,1,207,0,0,0,0,10,122,2,47],[0,0,0,0,8,8,4,59,0,0,1,0,7,112,0,137,0,0,0,0,8,120,2,47,0,0,0,0,7,120,1,207],[0,0,0,0,7,167,1,159,0,0,0,0,0,121,4,53,0,0,0,0,7,70,0,25,0,0,0,0,0,7,4,53],[0,0,0,31,4,64,0,57,0,0,2,121,4,64,1,151,0,0,0,0,6,70,0,25,0,0,0,0,4,86,0,73],[0,0,0,14,5,0,0,41,0,0,0,100,5,80,0,57,0,0,0,0,0,69,4,53,0,0,0,0,4,50,3,79],[0,0,0,31,3,16,1,143,0,0,0,0,2,22,4,54,0,0,0,5,5,16,2,114,0,0,7,177,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,116,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75],[0,0,7,169,0,0,65,61,0,0,0,0,6,3,0,75,0,0,7,192,0,0,97,61,0,0,0,5,5,80,2,16],[0,0,0,0,4,84,3,79,0,0,0,0,5,82,0,25,0,0,0,3,3,48,2,16,0,0,0,0,6,5,4,51],[0,0,0,0,6,54,1,207,0,0,0,0,6,54,2,47,0,0,0,0,4,4,4,59,0,0,1,0,3,48,0,137],[0,0,0,0,4,52,2,47,0,0,0,0,3,52,1,207,0,0,0,0,3,99,1,159,0,0,0,0,0,53,4,53],[0,0,0,0,3,18,0,25,0,0,0,0,0,3,4,53,0,0,0,31,1,16,0,57,0,0,2,122,1,16,1,151],[0,0,0,14,4,0,0,41,0,0,0,0,1,65,0,73,0,0,0,0,1,33,0,25,0,0,2,60,2,0,0,65],[0,0,2,60,3,64,0,156,0,0,0,0,3,2,0,25,0,0,0,0,3,4,64,25,0,0,0,64,3,48,2,16],[0,0,2,60,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,96,1,16,2,16,0,0,0,0,1,49,1,159],[0,0,0,0,3,0,4,20,0,0,2,60,4,48,0,156,0,0,0,0,3,2,128,25,0,0,0,192,2,48,2,16],[0,0,0,0,1,18,1,159,0,0,128,14,2,0,0,57,8,234,8,219,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,32,4,48,0,140,0,0,0,0,4,3,0,25],[0,0,0,32,4,0,128,57,0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,7,233,0,0,97,61],[0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16,0,0,0,14,9,128,0,41,0,0,0,0,8,129,3,79],[0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75],[0,0,7,225,0,0,65,61,0,0,0,0,7,5,0,75,0,0,7,248,0,0,97,61,0,0,0,5,6,96,2,16],[0,0,0,0,7,97,3,79,0,0,0,14,6,96,0,41,0,0,0,3,5,80,2,16,0,0,0,0,8,6,4,51],[0,0,0,0,8,88,1,207,0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,7,87,2,47,0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53],[0,0,0,1,2,32,1,144,0,0,8,30,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,96,2,16,1,143],[0,0,0,14,1,32,0,41,0,0,0,0,2,33,0,75,0,0,0,0,2,0,0,25,0,0,0,1,2,0,64,57],[0,0,2,67,4,16,0,156,0,0,1,219,0,0,33,61,0,0,0,1,2,32,1,144,0,0,1,219,0,0,193,61],[0,0,0,64,0,16,4,63,0,0,0,32,2,48,0,140,0,0,1,37,0,0,65,61,0,0,0,9,3,0,0,41],[0,0,0,11,2,48,0,108,0,0,8,59,0,0,193,61,0,0,0,14,1,0,0,41,0,0,0,0,1,1,4,51],[0,14,0,0,0,1,0,29,0,0,0,5,1,0,0,41,0,0,0,0,0,16,4,29,0,0,0,10,1,0,0,41],[0,0,0,12,2,0,0,41,8,234,8,68,0,0,4,15,0,0,0,1,2,0,0,57,0,0,0,0,0,18,4,29],[0,0,0,4,1,0,0,41,0,0,0,14,3,0,0,41,0,0,0,0,0,49,4,29,0,0,0,0,0,0,4,27],[0,0,0,0,0,2,4,27,0,0,0,0,0,1,4,27,0,0,0,13,1,0,0,41,0,0,0,0,0,1,4,27],[0,0,0,0,1,0,0,25,0,0,8,235,0,1,4,46,0,0,0,64,2,0,4,61,0,0,0,31,4,48,1,143],[0,0,0,5,5,48,2,114,0,0,8,43,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16],[0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53],[0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,8,35,0,0,65,61,0,0,0,0,6,4,0,75],[0,0,8,58,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79,0,0,0,0,5,82,0,25],[0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47],[0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207],[0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,1,67,0,0,1,61,0,0,0,100,2,16,0,57],[0,0,2,123,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,68,2,16,0,57,0,0,2,124,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,42,3,0,0,57,0,0,3,161,0,0,1,61],[0,0,0,0,3,0,4,20,0,0,0,0,4,18,0,25,0,0,0,0,2,36,0,75,0,0,0,0,5,0,0,25],[0,0,0,1,5,0,64,57,0,0,2,60,2,16,1,151,0,0,0,1,1,80,1,144,0,0,8,157,0,0,193,61],[0,0,0,0,1,0,0,49,0,0,0,0,5,65,0,75,0,0,8,157,0,0,65,61,0,0,0,1,2,32,3,103],[0,0,2,69,5,48,0,156,0,0,8,161,0,0,129,61,0,0,0,0,1,65,0,73,0,0,2,60,1,16,1,151],[0,0,0,0,1,18,3,223,0,0,0,192,2,48,2,16,0,0,2,70,2,32,1,151,0,0,2,71,2,32,1,199],[0,0,0,0,1,33,3,175,0,0,128,16,2,0,0,57,8,234,8,229,0,0,4,15,0,0,0,0,3,1,0,25],[0,0,0,96,3,48,2,112,0,0,2,60,3,48,1,151,0,0,0,1,2,32,1,144,0,0,8,168,0,0,97,61],[0,0,0,63,2,48,0,57,0,0,2,72,4,32,1,151,0,0,0,64,2,0,4,61,0,0,0,0,4,66,0,25],[0,0,0,0,5,36,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,2,67,6,64,0,156],[0,0,8,195,0,0,33,61,0,0,0,1,5,80,1,144,0,0,8,195,0,0,193,61,0,0,0,64,0,64,4,63],[0,0,0,0,4,50,4,54,0,0,0,31,5,48,0,57,0,0,0,5,5,80,2,114,0,0,8,123,0,0,97,61],[0,0,0,0,6,0,0,49,0,0,0,1,6,96,3,103,0,0,0,0,7,0,0,25,0,0,0,5,8,112,2,16],[0,0,0,0,9,132,0,25,0,0,0,0,8,134,3,79,0,0,0,0,8,8,4,59,0,0,0,0,0,137,4,53],[0,0,0,1,7,112,0,57,0,0,0,0,8,87,0,75,0,0,8,115,0,0,65,61,0,0,0,0,5,0,0,75],[0,0,8,125,0,0,97,61,0,0,0,31,5,48,1,143,0,0,0,5,3,48,2,114,0,0,8,137,0,0,97,61],[0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,116,0,25,0,0,0,0,7,113,3,79],[0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,54,0,75],[0,0,8,129,0,0,65,61,0,0,0,0,6,5,0,75,0,0,8,152,0,0,97,61,0,0,0,5,3,48,2,16],[0,0,0,0,1,49,3,79,0,0,0,0,3,52,0,25,0,0,0,3,5,80,2,16,0,0,0,0,6,3,4,51],[0,0,0,0,6,86,1,207,0,0,0,0,6,86,2,47,0,0,0,0,1,1,4,59,0,0,1,0,5,80,0,137],[0,0,0,0,1,81,2,47,0,0,0,0,1,81,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,19,4,53],[0,0,0,0,1,2,4,51,0,0,0,32,1,16,0,140,0,0,8,201,0,0,193,61,0,0,0,0,1,4,4,51],[0,0,0,0,0,1,4,45,0,0,2,126,1,0,0,65,0,0,0,0,0,16,4,53,0,0,0,17,1,0,0,57],[0,0,8,198,0,0,1,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,2,89,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,8,3,0,0,57,0,0,8,207,0,0,1,61],[0,0,0,31,4,48,1,143,0,0,0,5,2,48,2,114,0,0,8,179,0,0,97,61,0,0,0,0,5,0,0,25],[0,0,0,5,6,80,2,16,0,0,0,0,7,97,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,118,4,53],[0,0,0,1,5,80,0,57,0,0,0,0,6,37,0,75,0,0,8,172,0,0,65,61,0,0,0,0,5,4,0,75],[0,0,8,193,0,0,97,61,0,0,0,3,4,64,2,16,0,0,0,5,2,32,2,16,0,0,0,0,5,2,4,51],[0,0,0,0,5,69,1,207,0,0,0,0,5,69,2,47,0,0,0,0,1,33,3,79,0,0,0,0,1,1,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47,0,0,0,0,1,65,1,207,0,0,0,0,1,81,1,159],[0,0,0,0,0,18,4,53,0,0,0,96,1,48,2,16,0,0,8,236,0,1,4,48,0,0,2,126,1,0,0,65],[0,0,0,0,0,16,4,53,0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,2,127,1,0,0,65],[0,0,8,236,0,1,4,48,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,2,99,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,31,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,2,87,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,2,60,2,0,0,65,0,0,2,60,3,16,0,156,0,0,0,0,1,2,128,25],[0,0,0,64,1,16,2,16,0,0,2,88,1,16,1,199,0,0,8,236,0,1,4,48,0,0,8,222,0,33,4,33],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,8,227,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,8,232,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,8,234,0,0,4,50,0,0,8,235,0,1,4,46],[0,0,8,236,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,139,99,109],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,139,99,110],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,248,75,36],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,57,179,76,110],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,86,7,154,200],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0],[0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,255,224],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,159],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[138,200,76,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,63],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,127],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,0,0,0,0,0,0,0,0,0,0,0],[39,254,140,11,73,244,149,7,185,212,254,89,104,201,244,158,223,229,201,223,39,125,67,58,7,160,113,126,222,151,99,141],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[58,54,228,114,145,244,32,31,175,19,127,171,8,29,146,41,91,206,45,83,190,44,108,166,139,168,44,127,170,156,226,65],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[70,97,105,108,101,100,32,116,111,32,99,104,97,114,103,101,32,103,97,115,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[79,118,101,114,102,108,111,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,108,108,97,98,108,101,32,111,110,108,121,32,98,121,32,116,104,101,32,98,111,111,116,108,111,97,100,101,114,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,128,0,0,0,0,0,0,0,0],[0,0,8,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,160],[110,111,116,32,101,113,117,97,108,32,116,111,32,99,104,97,105,110,101,100,76,111,103,115,72,97,115,104,0,0,0,0],[114,101,99,111,110,115,116,114,117,99,116,101,100,67,104,97,105,110,101,100,76,111,103,115,72,97,115,104,32,105,115,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,7,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[114,171,238,69,181,158,52,74,248,166,229,32,36,28,71,68,175,242,110,212,17,244,196,176,15,138,240,154,218,218,67,186],[107,101,99,99,97,107,50,53,54,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0],[72,97,115,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[32,105,115,32,110,111,116,32,101,113,117,97,108,32,116,111,32,99,104,97,105,110,101,100,77,101,115,115,97,103,101,115],[114,101,99,111,110,115,116,114,117,99,116,101,100,67,104,97,105,110,101,100,77,101,115,115,97,103,101,115,72,97,115,104],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,164,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[112,111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[115,104,97,32,114,101,116,117,114,110,101,100,32,105,110,118,97,108,105,100,32,100,97,116,97,0,0,0,0,0,0,0],[0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[6,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[112,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[112,112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[97,105,110,101,100,76,49,66,121,116,101,99,111,100,101,115,82,101,118,101,97,108,68,97,116,97,72,97,115,104,0,0],[101,118,101,97,108,68,97,116,97,72,97,115,104,32,105,115,32,110,111,116,32,101,113,117,97,108,32,116,111,32,99,104],[114,101,99,111,110,115,116,114,117,99,116,101,100,67,104,97,105,110,101,100,76,49,66,121,116,101,99,111,100,101,115,82],[255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[105,115,109,97,116,99,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[115,116,97,116,101,32,100,105,102,102,32,99,111,109,112,114,101,115,115,105,111,110,32,118,101,114,115,105,111,110,32,109],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,239,65],[96,6,216,181,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,255,255,255,255,224],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,255,255,224],[100,97,116,97,32,97,114,114,97,121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[69,120,116,114,97,32,100,97,116,97,32,105,110,32,116,104,101,32,116,111,116,97,108,76,50,84,111,76,49,80,117,98],[76,49,32,77,101,115,115,101,110,103,101,114,32,112,117,98,100,97,116,97,32,105,115,32,116,111,111,32,108,111,110,103],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[84,111,111,32,109,97,110,121,32,76,50,45,62,76,49,32,108,111,103,115,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,128,0,0,0,0,0,0,0,0],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,116,104,101,32,99,97,108,108,101,114,32,116],[111,32,98,101,32,115,121,115,116,101,109,32,99,111,110,116,114,97,99,116,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[73,110,97,112,112,114,111,112,114,105,97,116,101,32,99,97,108,108,101,114,0,0,0,0,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,160,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,216],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[72,13,60,159,114,123,94,92,18,3,212,198,31,177,133,211,127,8,230,178,220,94,155,191,152,89,27,26,122,221,245,124],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[66,161,119,40,165,254,105,218,53,173,40,68,15,131,115,148,66,216,50,91,200,159,71,53,210,245,157,216,211,14,134,167]],"0x0000000000000000000000000000000000008010":[[0,0,0,1,2,32,1,144,0,0,0,20,0,0,193,61,0,0,0,96,2,16,2,16,0,0,0,9,2,32,1,151],[0,0,0,64,3,16,2,112,0,0,0,10,4,48,1,151,0,0,0,0,2,66,1,159,0,0,0,11,3,48,1,151],[0,0,0,0,2,50,1,159,0,0,0,12,2,32,1,199,0,0,0,96,1,16,2,112,0,0,0,10,1,16,1,151],[0,0,0,136,49,16,1,26,0,0,0,40,49,16,0,201,0,0,0,40,1,16,0,57,0,0,0,0,1,18,4,32],[0,0,0,0,1,1,0,75,0,0,0,25,0,0,193,61,0,0,0,0,1,0,0,25,0,0,0,29,0,1,4,48],[0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67,0,0,0,8,1,0,0,65],[0,0,0,28,0,1,4,46,0,0,0,13,1,0,0,65,0,0,0,28,0,1,4,46,0,0,0,27,0,0,4,50],[0,0,0,28,0,1,4,46,0,0,0,29,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[231,235,90,132,103,57,44,46,94,80,157,131,248,179,91,153,186,138,67,197,69,4,157,187,159,87,148,17,34,213,184,114]],"0x000000000000000000000000000000000000800f":[[0,3,0,0,0,0,0,2,0,4,0,0,0,0,0,2,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,65,3,48,1,151,0,2,0,0,0,49,3,85,0,1,0,0,0,1,3,85,0,0,0,128,8,0,0,57],[0,0,0,64,0,128,4,63,0,0,0,1,2,32,1,144,0,0,0,90,0,0,193,61,0,0,0,4,2,48,0,140],[0,0,0,98,0,0,65,61,0,0,0,0,2,1,4,59,0,0,0,67,2,32,1,151,0,0,0,68,2,32,0,156],[0,0,0,98,0,0,193,61,0,0,0,4,2,48,0,138,0,0,0,64,2,32,0,140,0,0,0,98,0,0,65,61],[0,0,0,4,2,16,3,112,0,0,0,0,9,2,4,59,0,0,0,69,2,144,0,156,0,0,0,98,0,0,33,61],[0,0,0,36,2,16,3,112,0,0,0,0,2,2,4,59,0,0,0,70,4,32,0,156,0,0,0,98,0,0,33,61],[0,0,0,35,4,32,0,57,0,0,0,71,5,0,0,65,0,0,0,0,6,52,0,75,0,0,0,0,6,0,0,25],[0,0,0,0,6,5,128,25,0,0,0,71,4,64,1,151,0,0,0,0,7,4,0,75,0,0,0,0,5,0,128,25],[0,0,0,71,4,64,0,156,0,0,0,0,5,6,192,25,0,0,0,0,4,5,0,75,0,0,0,98,0,0,193,61],[0,0,0,4,5,32,0,57,0,0,0,0,1,81,3,79,0,0,0,0,4,1,4,59,0,0,0,70,1,64,0,156],[0,0,0,98,0,0,33,61,0,0,0,0,1,66,0,25,0,0,0,36,1,16,0,57,0,0,0,0,1,49,0,75],[0,0,0,98,0,0,33,61,0,0,0,0,1,0,4,17,0,0,128,7,1,16,0,140,0,0,0,100,0,0,193,61],[0,1,0,0,0,5,0,29,0,2,0,0,0,4,0,29,0,4,0,0,0,8,0,29,0,0,0,76,1,0,0,65],[0,0,0,0,0,16,4,57,0,3,0,0,0,9,0,29,0,0,0,4,0,144,4,67,0,0,0,65,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,65,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,77,1,16,1,199,0,0,128,2,2,0,0,57,0,253,0,243,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,0,112,0,0,97,61,0,0,0,64,8,0,4,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,0,75],[0,0,0,113,0,0,193,61,0,0,0,68,1,128,0,57,0,0,0,81,3,0,0,65,0,0,0,0,0,49,4,53],[0,0,0,36,1,128,0,57,0,0,0,19,3,0,0,57,0,0,0,0,0,49,4,53,0,0,0,72,1,0,0,65],[0,0,0,0,0,24,4,53,0,0,0,4,1,128,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,49,4,53],[0,0,0,65,1,0,0,65,0,0,0,65,3,128,0,156,0,0,0,0,8,1,128,25,0,0,0,64,1,128,2,16],[0,0,0,82,1,16,1,199,0,0,0,255,0,1,4,48,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,0,98,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,66,1,0,0,65,0,0,0,254,0,1,4,46,0,0,0,0,1,0,0,25,0,0,0,255,0,1,4,48],[0,0,0,72,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63],[0,0,0,36,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,73,1,0,0,65,0,0,0,196,0,16,4,63],[0,0,0,74,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,75,1,0,0,65,0,0,0,255,0,1,4,48],[0,0,0,0,0,1,4,47,0,0,0,2,9,0,0,41,0,0,0,31,1,144,1,143,0,0,0,1,2,0,0,41],[0,0,0,32,3,32,0,57,0,0,0,1,3,48,3,103,0,0,0,5,4,144,2,114,0,0,0,129,0,0,97,61],[0,0,0,0,5,0,0,25,0,0,0,5,6,80,2,16,0,0,0,0,7,104,0,25,0,0,0,0,6,99,3,79],[0,0,0,0,6,6,4,59,0,0,0,0,0,103,4,53,0,0,0,1,5,80,0,57,0,0,0,0,6,69,0,75],[0,0,0,121,0,0,65,61,0,0,0,0,5,1,0,75,0,0,0,3,2,0,0,41,0,0,0,145,0,0,97,61],[0,0,0,5,4,64,2,16,0,0,0,0,3,67,3,79,0,0,0,0,4,72,0,25,0,0,0,3,1,16,2,16],[0,0,0,0,5,4,4,51,0,0,0,0,5,21,1,207,0,0,0,0,5,21,2,47,0,0,0,0,3,3,4,59],[0,0,1,0,1,16,0,137,0,0,0,0,3,19,2,47,0,0,0,0,1,19,1,207,0,0,0,0,1,81,1,159],[0,0,0,0,0,20,4,53,0,0,0,0,1,152,0,25,0,0,0,0,0,1,4,53,0,0,0,0,1,0,4,20],[0,0,0,4,3,32,0,140,0,0,0,153,0,0,193,61,0,0,0,0,3,0,0,49,0,0,0,0,2,0,0,25],[0,0,0,171,0,0,1,61,0,0,0,65,3,0,0,65,0,0,0,65,4,144,0,156,0,0,0,0,9,3,128,25],[0,0,0,96,4,144,2,16,0,0,0,65,5,128,0,156,0,0,0,0,8,3,128,25,0,0,0,64,5,128,2,16],[0,0,0,0,5,69,1,159,0,0,0,65,4,16,0,156,0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16],[0,0,0,0,1,81,1,159,0,253,0,248,0,0,4,15,0,0,0,1,2,32,1,95,0,2,0,0,0,1,3,85],[0,0,0,96,1,16,2,112,0,0,0,65,0,16,1,157,0,0,0,65,3,16,1,151,0,0,0,4,9,0,0,41],[0,0,0,96,1,0,0,57,0,0,0,0,4,3,0,75,0,0,0,187,0,0,193,61,0,0,0,1,2,32,1,144],[0,0,0,240,0,0,97,61,0,0,0,0,1,1,4,51,0,0,0,65,2,0,0,65,0,0,0,65,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,65,3,144,0,156,0,0,0,0,9,2,128,25,0,0,0,64,2,144,2,16],[0,0,0,96,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,255,0,1,4,48,0,0,0,78,1,48,0,156],[0,0,0,234,0,0,129,61,0,0,0,31,1,48,0,57,0,0,0,32,4,0,0,138,0,0,0,0,1,65,1,111],[0,0,0,63,1,16,0,57,0,0,0,0,4,65,1,111,0,0,0,64,1,0,4,61,0,0,0,0,4,65,0,25],[0,0,0,0,5,20,0,75,0,0,0,0,5,0,0,25,0,0,0,1,5,0,64,57,0,0,0,70,6,64,0,156],[0,0,0,234,0,0,33,61,0,0,0,1,5,80,1,144,0,0,0,234,0,0,193,61,0,0,0,64,0,64,4,63],[0,0,0,31,4,48,1,143,0,0,0,0,9,49,4,54,0,0,0,2,5,0,3,103,0,0,0,5,3,48,2,114],[0,0,0,218,0,0,97,61,0,0,0,0,6,0,0,25,0,0,0,5,7,96,2,16,0,0,0,0,8,121,0,25],[0,0,0,0,7,117,3,79,0,0,0,0,7,7,4,59,0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57],[0,0,0,0,7,54,0,75,0,0,0,210,0,0,65,61,0,0,0,0,6,4,0,75,0,0,0,175,0,0,97,61],[0,0,0,5,3,48,2,16,0,0,0,0,5,53,3,79,0,0,0,0,3,57,0,25,0,0,0,3,4,64,2,16],[0,0,0,0,6,3,4,51,0,0,0,0,6,70,1,207,0,0,0,0,6,70,2,47,0,0,0,0,5,5,4,59],[0,0,1,0,4,64,0,137,0,0,0,0,5,69,2,47,0,0,0,0,4,69,1,207,0,0,0,0,4,100,1,159],[0,0,0,0,0,67,4,53,0,0,0,175,0,0,1,61,0,0,0,79,1,0,0,65,0,0,0,0,0,16,4,53],[0,0,0,65,1,0,0,57,0,0,0,4,0,16,4,63,0,0,0,80,1,0,0,65,0,0,0,255,0,1,4,48],[0,0,0,0,1,0,0,25,0,0,0,254,0,1,4,46,0,0,0,0,0,1,4,47,0,0,0,246,0,33,4,35],[0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45],[0,0,0,251,0,33,4,37,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,0,253,0,0,4,50,0,0,0,254,0,1,4,46,0,0,0,255,0,1,4,48],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[201,135,51,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255],[128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[67,97,110,32,111,110,108,121,32,98,101,32,99,97,108,108,101,100,32,98,121,32,70,79,82,67,69,95,68,69,80,76],[79,89,69,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[24,6,170,24,150,187,242,101,104,232,132,167,55,75,65,224,2,80,9,98,202,186,106,21,2,58,141,144,232,80,139,131],[2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0],[78,72,123,113,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,0,0,0,0,0,0,0,0,0],[68,101,108,101,103,97,116,101,101,32,105,115,32,97,110,32,69,79,65,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[94,172,127,106,21,129,232,232,50,239,172,10,104,228,35,38,191,75,43,199,44,72,89,61,240,13,144,112,197,100,2,171]],"0x0000000000000000000000000000000000008003":[[0,1,0,0,0,0,0,2,0,5,0,0,0,0,0,2,0,0,0,0,6,1,3,79,0,0,0,0,0,6,3,85],[0,0,0,128,1,0,0,57,0,0,0,64,0,16,4,63,0,0,0,0,1,6,0,25,0,0,0,96,1,16,2,112],[0,0,0,187,1,16,1,151,0,0,0,1,3,32,1,144,0,0,0,38,0,0,193,61,0,0,0,4,3,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,0,3,6,4,59,0,0,0,224,3,48,2,112,0,0,0,189,4,48,0,156],[0,0,0,46,0,0,33,61,0,0,0,196,4,48,0,156,0,0,0,71,0,0,161,61,0,0,0,197,4,48,0,156],[0,0,1,0,0,0,97,61,0,0,0,198,2,48,0,156,0,0,1,25,0,0,97,61,0,0,0,199,2,48,0,156],[0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61],[0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112],[0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156,0,0,2,107,0,0,33,61,0,0,0,0,0,16,4,53],[0,0,0,32,0,0,4,63,0,0,1,43,0,0,1,61,0,0,0,0,1,0,4,22,0,0,0,0,1,1,0,75],[0,0,2,107,0,0,193,61,0,0,0,32,1,0,0,57,0,0,1,0,0,16,4,67,0,0,1,32,0,0,4,67],[0,0,0,188,1,0,0,65,0,0,2,231,0,1,4,46,0,0,0,190,4,48,0,156,0,0,0,99,0,0,161,61],[0,0,0,191,4,48,0,156,0,0,1,49,0,0,97,61,0,0,0,192,4,48,0,156,0,0,1,66,0,0,97,61],[0,0,0,193,2,48,0,156,0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75],[0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61],[0,0,0,4,1,96,3,112,0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156,0,0,2,107,0,0,33,61],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,0,1,0,0,25,2,230,2,202,0,0,4,15],[0,0,0,0,1,1,4,26,0,0,0,128,1,16,2,112,0,0,1,46,0,0,1,61,0,0,0,200,4,48,0,156],[0,0,0,115,0,0,97,61,0,0,0,201,2,48,0,156,0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156],[0,0,2,107,0,0,33,61,0,0,0,0,2,0,4,17,0,0,128,6,2,32,0,140,0,0,1,178,0,0,193,61],[0,5,0,0,0,1,0,29,2,230,2,109,0,0,4,15,0,0,0,0,1,1,4,26,0,4,0,0,0,1,0,29],[0,0,0,5,1,0,0,41,2,230,2,109,0,0,4,15,0,0,0,4,3,0,0,41,0,0,0,218,2,48,0,65],[0,0,0,0,0,33,4,27,0,0,0,128,1,48,2,112,0,0,1,135,0,0,1,61,0,0,0,194,2,48,0,156],[0,0,0,207,0,0,97,61,0,0,0,195,2,48,0,156,0,0,2,107,0,0,193,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156],[0,0,2,107,0,0,33,61,2,230,2,125,0,0,4,15,0,0,1,135,0,0,1,61,0,0,0,0,3,0,4,22],[0,0,0,0,3,3,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,64,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,0,3,0,4,17,0,0,0,36,1,96,3,112,0,0,0,0,5,1,4,59],[0,0,0,4,1,96,3,112,0,0,0,0,4,1,4,59,0,0,0,2,1,32,1,144,0,0,0,130,0,0,193,61],[0,0,0,219,1,48,0,156,0,0,1,77,0,0,129,61,0,5,0,0,0,5,0,29,0,4,0,0,0,4,0,29],[0,0,0,220,1,0,0,65,0,0,0,128,0,16,4,63,0,3,0,0,0,3,0,29,0,0,0,202,1,48,1,151],[0,2,0,0,0,1,0,29,0,0,0,132,0,16,4,63,0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,221,1,16,1,199],[0,0,128,6,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,0,3,1,0,25,0,0,0,96,3,48,2,112],[0,0,0,187,3,48,1,151,0,0,0,64,4,48,0,140,0,0,0,0,4,3,0,25,0,0,0,64,4,0,128,57],[0,0,0,31,5,64,1,143,0,0,0,5,6,64,2,114,0,0,0,164,0,0,97,61,0,0,0,0,7,0,0,25],[0,0,0,5,8,112,2,16,0,0,0,0,9,129,3,79,0,0,0,0,9,9,4,59,0,0,0,128,8,128,0,57],[0,0,0,0,0,152,4,53,0,0,0,1,7,112,0,57,0,0,0,0,8,103,0,75,0,0,0,156,0,0,65,61],[0,0,0,0,7,5,0,75,0,0,0,179,0,0,97,61,0,0,0,5,6,96,2,16,0,0,0,0,7,97,3,79],[0,0,0,3,5,80,2,16,0,0,0,128,6,96,0,57,0,0,0,0,8,6,4,51,0,0,0,0,8,88,1,207],[0,0,0,0,8,88,2,47,0,0,0,0,7,7,4,59,0,0,1,0,5,80,0,137,0,0,0,0,7,87,2,47],[0,0,0,0,5,87,1,207,0,0,0,0,5,133,1,159,0,0,0,0,0,86,4,53,0,0,0,1,2,32,1,144],[0,0,1,143,0,0,97,61,0,0,0,31,1,64,0,57,0,0,0,224,1,16,1,143,0,0,0,128,2,16,0,57],[0,0,0,64,0,32,4,63,0,0,0,64,3,48,0,140,0,0,2,107,0,0,65,61,0,0,0,192,3,16,0,57],[0,0,0,64,0,48,4,63,0,0,0,128,3,0,4,61,0,0,0,1,4,48,0,140,0,0,2,107,0,0,33,61],[0,0,0,0,0,50,4,53,0,0,0,160,2,0,4,61,0,0,0,1,3,32,0,140,0,0,2,107,0,0,33,61],[0,0,0,160,1,16,0,57,0,0,0,0,0,33,4,53,0,0,0,5,1,0,0,107,0,0,1,245,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,225,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,30,3,0,0,57,0,0,1,194,0,0,1,61,0,0,0,0,2,0,4,22],[0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,96,1,16,0,140],[0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,3,1,4,59,0,0,0,202,1,48,0,156],[0,0,2,107,0,0,33,61,0,0,0,68,1,96,3,112,0,0,0,0,2,1,4,59,0,0,0,0,1,2,0,75],[0,0,0,0,1,0,0,25,0,0,0,1,1,0,192,57,0,5,0,0,0,2,0,29,0,0,0,0,1,18,0,75],[0,0,2,107,0,0,193,61,0,0,0,36,1,96,3,112,0,0,0,0,1,1,4,59,0,3,0,0,0,1,0,29],[0,0,0,0,0,48,4,53,0,0,0,32,0,0,4,63,0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20],[0,4,0,0,0,3,0,29,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,4,3,0,0,41],[0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26],[0,0,0,205,1,16,1,151,0,0,0,3,1,16,0,108,0,0,1,206,0,0,161,61,0,0,0,5,1,0,0,107],[0,0,2,63,0,0,193,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,211,3,0,0,65],[0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,28,3,0,0,57,0,0,1,194,0,0,1,61],[0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75,0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138],[0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112,0,0,0,0,3,1,4,59],[0,0,0,2,1,32,1,144,0,0,1,13,0,0,193,61,0,0,0,0,1,0,4,17,0,0,255,255,1,16,0,140],[0,0,1,77,0,0,33,61,0,0,0,212,1,48,0,156,0,0,1,120,0,0,65,61,0,0,0,207,1,0,0,65],[0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,48,1,0,0,57],[0,0,0,164,0,16,4,63,0,0,0,213,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,214,1,0,0,65],[0,0,1,86,0,0,1,61,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61],[0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,0,1,0,4,17],[0,0,0,0,0,16,4,53,0,0,0,1,1,0,0,57,0,0,0,32,0,16,4,63,0,0,0,0,1,0,0,25],[0,5,0,0,0,6,3,83,2,230,2,202,0,0,4,15,0,0,0,5,2,0,3,95,0,0,0,4,2,32,3,112],[0,0,0,0,2,2,4,59,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,0,25],[2,230,2,202,0,0,4,15,0,0,0,0,1,1,4,26,0,0,0,128,0,16,4,63,0,0,0,203,1,0,0,65],[0,0,2,231,0,1,4,46,0,0,0,0,2,0,4,22,0,0,0,0,2,2,0,75,0,0,2,107,0,0,193,61],[0,0,0,4,1,16,0,138,0,0,0,64,1,16,0,140,0,0,2,107,0,0,65,61,0,0,0,4,1,96,3,112],[0,0,0,0,1,1,4,59,0,0,0,202,2,16,0,156,0,0,2,107,0,0,33,61,0,0,0,36,2,96,3,112],[0,0,0,0,2,2,4,59,2,230,2,144,0,0,4,15,0,0,0,0,1,1,0,75,0,0,0,0,1,0,0,25],[0,0,0,1,1,0,192,57,0,0,1,135,0,0,1,61,0,0,0,0,3,0,4,22,0,0,0,0,3,3,0,75],[0,0,2,107,0,0,193,61,0,0,0,4,1,16,0,138,0,0,0,32,1,16,0,140,0,0,2,107,0,0,65,61],[0,0,0,0,3,0,4,17,0,0,0,2,1,32,1,144,0,0,1,89,0,0,193,61,0,0,255,255,1,48,0,140],[0,0,1,89,0,0,161,61,0,0,0,207,1,0,0,65,0,0,0,128,0,16,4,63,0,0,0,32,1,0,0,57],[0,0,0,132,0,16,4,63,0,0,0,36,1,0,0,57,0,0,0,164,0,16,4,63,0,0,0,226,1,0,0,65],[0,0,0,196,0,16,4,63,0,0,0,227,1,0,0,65,0,0,0,228,0,16,4,63,0,0,0,215,1,0,0,65],[0,0,2,232,0,1,4,48,0,5,0,0,0,3,0,29,0,0,0,0,0,48,4,53,0,0,0,32,0,0,4,63],[0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,4,2,0,0,57,0,0,0,0,2,32,3,103],[0,0,0,0,2,2,4,59,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,205,3,16,1,151],[0,0,0,0,2,35,0,75,0,0,1,188,0,0,193,61,0,0,0,5,2,0,0,41,0,0,0,0,0,32,4,53],[0,0,0,32,0,0,4,63,0,5,0,1,0,16,0,61,0,0,0,0,1,0,0,25,2,230,2,202,0,0,4,15],[0,0,0,5,2,0,0,41,0,0,0,0,0,33,4,27,0,0,0,0,1,0,0,25,0,0,2,231,0,1,4,46],[0,0,0,0,1,0,4,17,0,4,0,0,0,1,0,29,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,0,1,0,0,25,0,5,0,0,0,3,0,29,2,230,2,202,0,0,4,15,0,0,0,0,1,1,4,26],[0,3,0,0,0,1,0,29,0,0,0,4,1,0,0,41,2,230,2,109,0,0,4,15,0,0,0,3,3,0,0,41],[0,0,0,5,2,48,0,41,0,0,0,0,0,33,4,27,0,0,0,205,1,48,1,151,0,0,0,64,2,0,4,61],[0,0,0,0,0,18,4,53,0,0,0,187,1,0,0,65,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,64,1,32,2,16,0,0,0,209,1,16,1,199,0,0,2,231,0,1,4,46,0,0,0,64,2,0,4,61],[0,0,0,31,4,48,1,143,0,0,0,5,5,48,2,114,0,0,1,156,0,0,97,61,0,0,0,0,6,0,0,25],[0,0,0,5,7,96,2,16,0,0,0,0,8,114,0,25,0,0,0,0,7,113,3,79,0,0,0,0,7,7,4,59],[0,0,0,0,0,120,4,53,0,0,0,1,6,96,0,57,0,0,0,0,7,86,0,75,0,0,1,148,0,0,65,61],[0,0,0,0,6,4,0,75,0,0,1,171,0,0,97,61,0,0,0,5,5,80,2,16,0,0,0,0,1,81,3,79],[0,0,0,0,5,82,0,25,0,0,0,3,4,64,2,16,0,0,0,0,6,5,4,51,0,0,0,0,6,70,1,207],[0,0,0,0,6,70,2,47,0,0,0,0,1,1,4,59,0,0,1,0,4,64,0,137,0,0,0,0,1,65,2,47],[0,0,0,0,1,65,1,207,0,0,0,0,1,97,1,159,0,0,0,0,0,21,4,53,0,0,0,187,1,0,0,65],[0,0,0,187,4,32,0,156,0,0,0,0,2,1,128,25,0,0,0,64,1,32,2,16,0,0,0,96,2,48,2,16],[0,0,0,0,1,33,1,159,0,0,2,232,0,1,4,48,0,0,0,207,1,0,0,65,0,0,0,128,0,16,4,63],[0,0,0,32,1,0,0,57,0,0,0,132,0,16,4,63,0,0,0,61,1,0,0,57,0,0,0,164,0,16,4,63],[0,0,0,216,1,0,0,65,0,0,0,196,0,16,4,63,0,0,0,217,1,0,0,65,0,0,1,86,0,0,1,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,206,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,36,2,16,0,57,0,0,0,15,3,0,0,57,0,0,0,0,0,50,4,53,0,0,0,207,2,0,0,65],[0,0,0,0,0,33,4,53,0,0,0,4,2,16,0,57,0,0,0,32,3,0,0,57,0,0,0,0,0,50,4,53],[0,0,0,187,2,0,0,65,0,0,0,187,3,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,208,1,16,1,199,0,0,2,232,0,1,4,48,0,0,0,0,0,48,4,53,0,0,0,1,1,0,0,57],[0,0,0,32,0,16,4,63,0,0,0,187,3,0,0,65,0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57],[2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,3,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,0,1,1,0,75,0,0,0,247,0,0,193,61],[0,0,0,5,1,0,0,107,0,0,2,63,0,0,97,61,0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57],[0,0,0,210,3,0,0,65,0,0,0,0,0,50,4,53,0,0,0,36,2,16,0,57,0,0,0,29,3,0,0,57],[0,0,1,194,0,0,1,61,0,0,0,0,1,2,0,75,0,0,2,13,0,0,193,61,0,0,0,4,1,0,0,107],[0,0,2,13,0,0,97,61,0,0,0,2,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,4,2,0,0,41,0,1,0,1,0,32,0,146],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,205,1,16,1,151,0,0,0,1,1,16,0,108],[0,0,2,65,0,0,161,61,0,0,0,3,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,1,1,0,0,57],[0,0,0,32,0,16,4,63,0,0,0,187,3,0,0,65,0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57],[2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,4,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,5,2,0,0,41,0,0,0,0,0,33,4,27,0,0,0,64,1,0,4,61],[0,0,0,0,0,33,4,53,0,0,0,187,2,0,0,65,0,0,0,0,3,0,4,20,0,0,0,187,4,48,0,156],[0,0,0,0,3,2,128,25,0,0,0,187,4,16,0,156,0,0,0,0,1,2,128,25,0,0,0,64,1,16,2,16],[0,0,0,192,2,48,2,16,0,0,0,0,1,18,1,159,0,0,0,223,1,16,1,199,0,0,128,13,2,0,0,57],[0,0,0,3,3,0,0,57,0,0,0,224,4,0,0,65,0,0,0,3,5,0,0,41,0,0,0,4,6,0,0,41],[2,230,2,220,0,0,4,15,0,0,0,1,1,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,0,0,25],[0,0,2,231,0,1,4,46,0,0,0,2,1,0,0,41,0,0,0,0,0,16,4,53,0,0,0,1,1,0,0,57],[0,0,0,32,0,16,4,63,0,0,0,187,3,0,0,65,0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156],[0,0,0,0,1,3,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57],[2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61,0,0,0,0,1,1,4,59],[0,0,0,1,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,107,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,0,1,1,0,75,0,0,2,13,0,0,193,61],[0,0,0,64,1,0,4,61,0,0,0,68,2,16,0,57,0,0,0,222,3,0,0,65,0,0,0,0,0,50,4,53],[0,0,0,207,2,0,0,65,0,0,0,0,0,33,4,53,0,0,0,36,2,16,0,57,0,0,0,32,3,0,0,57],[0,0,0,0,0,50,4,53,0,0,0,4,2,16,0,57,0,0,1,199,0,0,1,61,0,0,0,0,1,0,0,25],[0,0,2,232,0,1,4,48,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,187,1,0,0,65],[0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16],[0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,2,123,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25],[0,0,2,232,0,1,4,48,0,0,0,202,1,16,1,151,0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63],[0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20,0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25],[0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15],[0,0,0,1,2,32,1,144,0,0,2,142,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26],[0,0,0,205,1,16,1,151,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,2,232,0,1,4,48],[0,2,0,0,0,0,0,2,0,2,0,0,0,2,0,29,0,0,0,202,1,16,1,151,0,1,0,0,0,1,0,29],[0,0,0,0,0,16,4,53,0,0,0,32,0,0,4,63,0,0,0,187,1,0,0,65,0,0,0,0,2,0,4,20],[0,0,0,187,3,32,0,156,0,0,0,0,2,1,128,25,0,0,0,192,1,32,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,200,0,0,97,61],[0,0,0,1,2,0,0,57,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,205,1,16,1,151],[0,0,0,2,1,16,0,108,0,0,2,198,0,0,33,61,0,0,0,1,1,0,0,41,0,0,0,0,0,16,4,53],[0,0,0,1,1,0,0,57,0,0,0,32,0,16,4,63,0,0,0,187,4,0,0,65,0,0,0,0,1,0,4,20],[0,0,0,187,2,16,0,156,0,0,0,0,1,4,128,25,0,0,0,192,1,16,2,16,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,200,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,2,2,0,0,41,0,0,0,0,0,32,4,53,0,0,0,32,0,16,4,63],[0,0,0,0,1,0,4,20,0,0,0,187,2,16,0,156,0,0,0,187,1,0,128,65,0,0,0,192,1,16,2,16],[0,0,0,204,1,16,1,199,0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144],[0,0,2,200,0,0,97,61,0,0,0,0,1,1,4,59,0,0,0,0,1,1,4,26,0,0,0,0,1,1,0,75],[0,0,0,0,2,0,0,25,0,0,0,1,2,0,192,57,0,0,0,1,1,32,1,143,0,0,0,0,0,1,4,45],[0,0,0,0,1,0,0,25,0,0,2,232,0,1,4,48,0,0,0,187,2,0,0,65,0,0,0,187,3,16,0,156],[0,0,0,0,1,2,128,25,0,0,0,0,3,0,4,20,0,0,0,187,4,48,0,156,0,0,0,0,3,2,128,25],[0,0,0,192,2,48,2,16,0,0,0,64,1,16,2,16,0,0,0,0,1,33,1,159,0,0,0,204,1,16,1,199],[0,0,128,16,2,0,0,57,2,230,2,225,0,0,4,15,0,0,0,1,2,32,1,144,0,0,2,218,0,0,97,61],[0,0,0,0,1,1,4,59,0,0,0,0,0,1,4,45,0,0,0,0,1,0,0,25,0,0,2,232,0,1,4,48],[0,0,2,223,0,33,4,33,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45,0,0,0,0,2,0,0,25],[0,0,0,0,0,1,4,45,0,0,2,228,0,33,4,35,0,0,0,1,2,0,0,57,0,0,0,0,0,1,4,45],[0,0,0,0,2,0,0,25,0,0,0,0,0,1,4,45,0,0,2,230,0,0,4,50,0,0,2,231,0,1,4,46],[0,0,2,232,0,1,4,48,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255],[0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,1,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,225,220,31],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,202,183,232,234],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,202,183,232,235],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,225,35,156,216],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,251,26,154,87],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,225,220,32],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,137,105,9,220],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,167,128,145],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,167,128,146],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,211,93,24],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,169,182,181],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,95,210,122],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,99,149,198],[0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,128,0,0,0,0,0,0,0,0],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255],[73,110,99,111,114,114,101,99,116,32,110,111,110,99,101,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[8,195,121,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[84,104,101,32,110,111,110,99,101,32,119,97,115,32,110,111,116,32,115,101,116,32,97,115,32,117,115,101,100,0,0,0],[82,101,117,115,105,110,103,32,116,104,101,32,115,97,109,101,32,110,111,110,99,101,32,116,119,105,99,101,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1],[84,104,101,32,118,97,108,117,101,32,102,111,114,32,105,110,99,114,101,109,101,110,116,105,110,103,32,116,104,101,32,110],[111,110,99,101,32,105,115,32,116,111,111,32,104,105,103,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,132,0,0,0,128,0,0,0,0,0,0,0,0],[79,110,108,121,32,116,104,101,32,99,111,110,116,114,97,99,116,32,100,101,112,108,111,121,101,114,32,99,97,110,32,105],[110,99,114,101,109,101,110,116,32,116,104,101,32,100,101,112,108,111,121,109,101,110,116,32,110,111,110,99,101,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0],[123,81,15,232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,0,0,0,128,0,0,0,0,0,0,0,0],[80,114,101,118,105,111,117,115,32,110,111,110,99,101,32,104,97,115,32,110,111,116,32,98,101,101,110,32,117,115,101,100],[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0],[218,43,113,110,90,93,95,96,43,154,88,66,188,216,156,33,91,18,82,88,223,234,39,26,3,229,224,232,1,217,58,140],[78,111,110,99,101,32,118,97,108,117,101,32,99,97,110,110,111,116,32,98,101,32,115,101,116,32,116,111,32,48,0,0],[84,104,105,115,32,109,101,116,104,111,100,32,114,101,113,117,105,114,101,32,115,121,115,116,101,109,32,99,97,108,108,32],[102,108,97,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],[205,38,218,213,70,69,248,169,15,229,84,69,140,55,53,181,164,198,188,161,173,181,140,218,24,152,223,38,173,188,41,218]]}} \ No newline at end of file From e75aa11f2d3e6c9eb50543f896e3dfca8cca90d2 Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Wed, 21 Feb 2024 19:44:28 +0200 Subject: [PATCH 020/106] fix(contract-verifier): Add force_evmla flag (#1179) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - adds force_evmla flag ## Why ❔ - it should be processed explicitly by verifier to pass `--force-evmla` to zksolc ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- core/bin/contract-verifier/src/verifier.rs | 1 + core/bin/contract-verifier/src/zksolc_utils.rs | 8 +++++++- ...6b7923c9e03def94f4bf4674def1893e2232be80f57a0.json} | 5 +++-- ...8a060325677d57040037da0e07cef2c7b7246851a3703.json} | 10 ++++++++-- ...faa8fd345094de508af93f4085be7cf3b54b1e8ecdadd.json} | 10 ++++++++-- ...d_force_evmla_to_contract_verification_req.down.sql | 1 + ...add_force_evmla_to_contract_verification_req.up.sql | 1 + core/lib/dal/src/contract_verification_dal.rs | 10 +++++++--- .../lib/dal/src/models/storage_verification_request.rs | 2 ++ core/lib/types/src/contract_verification_api.rs | 2 ++ docker/contract-verifier/Dockerfile | 8 ++++++++ 11 files changed, 48 insertions(+), 10 deletions(-) rename core/lib/dal/.sqlx/{query-1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4.json => query-40c17194a2089a7d3fa6b7923c9e03def94f4bf4674def1893e2232be80f57a0.json} (68%) rename core/lib/dal/.sqlx/{query-1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5.json => query-5d341e334cbc2d38efc8a060325677d57040037da0e07cef2c7b7246851a3703.json} (90%) rename core/lib/dal/.sqlx/{query-5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c.json => query-a115f795672787fe25bfaa8fd345094de508af93f4085be7cf3b54b1e8ecdadd.json} (78%) create mode 100644 core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.down.sql create mode 100644 core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.up.sql diff --git a/core/bin/contract-verifier/src/verifier.rs b/core/bin/contract-verifier/src/verifier.rs index f75d69bbc342..ab9451240f78 100644 --- a/core/bin/contract-verifier/src/verifier.rs +++ b/core/bin/contract-verifier/src/verifier.rs @@ -310,6 +310,7 @@ impl ContractVerifier { let settings = Settings { output_selection: Some(default_output_selection), is_system: request.req.is_system, + force_evmla: request.req.force_evmla, other: serde_json::Value::Object( vec![("optimizer".to_string(), optimizer_value)] .into_iter() diff --git a/core/bin/contract-verifier/src/zksolc_utils.rs b/core/bin/contract-verifier/src/zksolc_utils.rs index db1fcf0a96d7..90bf19dd337c 100644 --- a/core/bin/contract-verifier/src/zksolc_utils.rs +++ b/core/bin/contract-verifier/src/zksolc_utils.rs @@ -35,7 +35,7 @@ pub struct Source { } /// Compiler settings. -/// There are fields like `output_selection` and `is_system` which are accessed by contract verifier explicitly. +/// There are fields like `output_selection`, `is_system`, `force_evmla` which are accessed by contract verifier explicitly. /// Other fields are accumulated in `other`, this way every field that was in the original request will be passed to a compiler. #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -45,6 +45,9 @@ pub struct Settings { /// Flag for system compilation mode. #[serde(default)] pub is_system: bool, + /// Flag to force `evmla` IR. + #[serde(default)] + pub force_evmla: bool, /// Other fields. #[serde(flatten)] pub other: serde_json::Value, @@ -103,6 +106,9 @@ impl ZkSolc { if input.settings.is_system { command.arg("--system-mode"); } + if input.settings.force_evmla { + command.arg("--force-evmla"); + } } command .arg("--solc") diff --git a/core/lib/dal/.sqlx/query-1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4.json b/core/lib/dal/.sqlx/query-40c17194a2089a7d3fa6b7923c9e03def94f4bf4674def1893e2232be80f57a0.json similarity index 68% rename from core/lib/dal/.sqlx/query-1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4.json rename to core/lib/dal/.sqlx/query-40c17194a2089a7d3fa6b7923c9e03def94f4bf4674def1893e2232be80f57a0.json index 7531f7ed4c00..c655704fd842 100644 --- a/core/lib/dal/.sqlx/query-1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4.json +++ b/core/lib/dal/.sqlx/query-40c17194a2089a7d3fa6b7923c9e03def94f4bf4674def1893e2232be80f57a0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO\n contract_verification_requests (\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'queued', NOW(), NOW())\n RETURNING\n id\n ", + "query": "\n INSERT INTO\n contract_verification_requests (\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system,\n force_evmla,\n status,\n created_at,\n updated_at\n )\n VALUES\n ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'queued', NOW(), NOW())\n RETURNING\n id\n ", "describe": { "columns": [ { @@ -19,6 +19,7 @@ "Bool", "Text", "Bytea", + "Bool", "Bool" ] }, @@ -26,5 +27,5 @@ false ] }, - "hash": "1d6b698b241cb6c5efd070a98165f6760cfeac185330d1d9c5cdb5b383ed8ed4" + "hash": "40c17194a2089a7d3fa6b7923c9e03def94f4bf4674def1893e2232be80f57a0" } diff --git a/core/lib/dal/.sqlx/query-1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5.json b/core/lib/dal/.sqlx/query-5d341e334cbc2d38efc8a060325677d57040037da0e07cef2c7b7246851a3703.json similarity index 90% rename from core/lib/dal/.sqlx/query-1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5.json rename to core/lib/dal/.sqlx/query-5d341e334cbc2d38efc8a060325677d57040037da0e07cef2c7b7246851a3703.json index a9d5b42d2148..f0d8b01d57c0 100644 --- a/core/lib/dal/.sqlx/query-1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5.json +++ b/core/lib/dal/.sqlx/query-5d341e334cbc2d38efc8a060325677d57040037da0e07cef2c7b7246851a3703.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE contract_verification_requests\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id = (\n SELECT\n id\n FROM\n contract_verification_requests\n WHERE\n status = 'queued'\n OR (\n status = 'in_progress'\n AND processing_started_at < NOW() - $1::INTERVAL\n )\n ORDER BY\n created_at\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system\n ", + "query": "\n UPDATE contract_verification_requests\n SET\n status = 'in_progress',\n attempts = attempts + 1,\n updated_at = NOW(),\n processing_started_at = NOW()\n WHERE\n id = (\n SELECT\n id\n FROM\n contract_verification_requests\n WHERE\n status = 'queued'\n OR (\n status = 'in_progress'\n AND processing_started_at < NOW() - $1::INTERVAL\n )\n ORDER BY\n created_at\n LIMIT\n 1\n FOR UPDATE\n SKIP LOCKED\n )\n RETURNING\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system,\n force_evmla\n ", "describe": { "columns": [ { @@ -52,6 +52,11 @@ "ordinal": 9, "name": "is_system", "type_info": "Bool" + }, + { + "ordinal": 10, + "name": "force_evmla", + "type_info": "Bool" } ], "parameters": { @@ -69,8 +74,9 @@ false, true, false, + false, false ] }, - "hash": "1c60010ded4e79886890a745a050fa6d65c05d8144bdfd143480834ead4bd8d5" + "hash": "5d341e334cbc2d38efc8a060325677d57040037da0e07cef2c7b7246851a3703" } diff --git a/core/lib/dal/.sqlx/query-5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c.json b/core/lib/dal/.sqlx/query-a115f795672787fe25bfaa8fd345094de508af93f4085be7cf3b54b1e8ecdadd.json similarity index 78% rename from core/lib/dal/.sqlx/query-5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c.json rename to core/lib/dal/.sqlx/query-a115f795672787fe25bfaa8fd345094de508af93f4085be7cf3b54b1e8ecdadd.json index b57400c28f5e..ebe8ce232cfb 100644 --- a/core/lib/dal/.sqlx/query-5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c.json +++ b/core/lib/dal/.sqlx/query-a115f795672787fe25bfaa8fd345094de508af93f4085be7cf3b54b1e8ecdadd.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system\n FROM\n contract_verification_requests\n WHERE\n status = 'successful'\n ORDER BY\n id\n ", + "query": "\n SELECT\n id,\n contract_address,\n source_code,\n contract_name,\n zk_compiler_version,\n compiler_version,\n optimization_used,\n optimizer_mode,\n constructor_arguments,\n is_system,\n force_evmla\n FROM\n contract_verification_requests\n WHERE\n status = 'successful'\n ORDER BY\n id\n ", "describe": { "columns": [ { @@ -52,6 +52,11 @@ "ordinal": 9, "name": "is_system", "type_info": "Bool" + }, + { + "ordinal": 10, + "name": "force_evmla", + "type_info": "Bool" } ], "parameters": { @@ -67,8 +72,9 @@ false, true, false, + false, false ] }, - "hash": "5f6885b5457aaa78e10917ae5b8cd0bc0e8923a6bae64f22f09242766835ee0c" + "hash": "a115f795672787fe25bfaa8fd345094de508af93f4085be7cf3b54b1e8ecdadd" } diff --git a/core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.down.sql b/core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.down.sql new file mode 100644 index 000000000000..48bb0390490f --- /dev/null +++ b/core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.down.sql @@ -0,0 +1 @@ +ALTER TABLE contract_verification_requests DROP COLUMN force_evmla; diff --git a/core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.up.sql b/core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.up.sql new file mode 100644 index 000000000000..e4dad0a0a435 --- /dev/null +++ b/core/lib/dal/migrations/20240221155945_add_force_evmla_to_contract_verification_req.up.sql @@ -0,0 +1 @@ +ALTER TABLE contract_verification_requests ADD COLUMN IF NOT EXISTS force_evmla BOOLEAN NOT NULL DEFAULT false; diff --git a/core/lib/dal/src/contract_verification_dal.rs b/core/lib/dal/src/contract_verification_dal.rs index af4f3188a2dd..d3776a15cd7f 100644 --- a/core/lib/dal/src/contract_verification_dal.rs +++ b/core/lib/dal/src/contract_verification_dal.rs @@ -73,12 +73,13 @@ impl ContractVerificationDal<'_, '_> { optimizer_mode, constructor_arguments, is_system, + force_evmla, status, created_at, updated_at ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9, 'queued', NOW(), NOW()) + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'queued', NOW(), NOW()) RETURNING id "#, @@ -92,6 +93,7 @@ impl ContractVerificationDal<'_, '_> { query.optimizer_mode, query.constructor_arguments.0, query.is_system, + query.force_evmla, ) .fetch_one(self.storage.conn()) .await @@ -149,7 +151,8 @@ impl ContractVerificationDal<'_, '_> { optimization_used, optimizer_mode, constructor_arguments, - is_system + is_system, + force_evmla "#, &processing_timeout ) @@ -469,7 +472,8 @@ impl ContractVerificationDal<'_, '_> { optimization_used, optimizer_mode, constructor_arguments, - is_system + is_system, + force_evmla FROM contract_verification_requests WHERE diff --git a/core/lib/dal/src/models/storage_verification_request.rs b/core/lib/dal/src/models/storage_verification_request.rs index e6c68ca16fd9..61895fab76d3 100644 --- a/core/lib/dal/src/models/storage_verification_request.rs +++ b/core/lib/dal/src/models/storage_verification_request.rs @@ -18,6 +18,7 @@ pub struct StorageVerificationRequest { pub optimizer_mode: Option, pub constructor_arguments: Vec, pub is_system: bool, + pub force_evmla: bool, } impl From for VerificationRequest { @@ -44,6 +45,7 @@ impl From for VerificationRequest { optimizer_mode: value.optimizer_mode, constructor_arguments: value.constructor_arguments.into(), is_system: value.is_system, + force_evmla: value.force_evmla, }, } } diff --git a/core/lib/types/src/contract_verification_api.rs b/core/lib/types/src/contract_verification_api.rs index 02a5bef727dc..5be7a18be0eb 100644 --- a/core/lib/types/src/contract_verification_api.rs +++ b/core/lib/types/src/contract_verification_api.rs @@ -142,6 +142,8 @@ pub struct VerificationIncomingRequest { pub constructor_arguments: Bytes, #[serde(default)] pub is_system: bool, + #[serde(default)] + pub force_evmla: bool, } #[derive(Debug, Eq, PartialEq, Clone, Copy)] diff --git a/docker/contract-verifier/Dockerfile b/docker/contract-verifier/Dockerfile index e7991a950bef..e6c700ac7303 100644 --- a/docker/contract-verifier/Dockerfile +++ b/docker/contract-verifier/Dockerfile @@ -21,6 +21,14 @@ RUN skip_versions="v1.3.12 v1.3.15 v1.3.20" && \ chmod +x /etc/zksolc-bin/$VERSION/zksolc; \ done +# install zksolc 1.4.x +RUN for VERSION in $(seq -f "v1.4.%g" 0 0); do \ + mkdir -p /etc/zksolc-bin/$VERSION && \ + wget https://github.com/matter-labs/zksolc-bin/raw/main/linux-amd64/zksolc-linux-amd64-musl-$VERSION -O /etc/zksolc-bin/$VERSION/zksolc && \ + chmod +x /etc/zksolc-bin/$VERSION/zksolc; \ + done + + # install zkvyper 1.3.x RUN for VERSION in $(seq -f "v1.3.%g" 9 17); do \ mkdir -p /etc/zkvyper-bin/$VERSION && \ From 4f41b68b038526423aeed98af96cd7b801273172 Mon Sep 17 00:00:00 2001 From: AnastasiiaVashchuk <72273339+AnastasiiaVashchuk@users.noreply.github.com> Date: Wed, 21 Feb 2024 20:00:13 +0200 Subject: [PATCH 021/106] feat(node_framework): Support Eth Watch in the framework (#1145) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - Small change in the `EthWatch` component. Now `Eth Watch` 's `pool` field is used instead of `ConnectionPool` passed in the Eth Watch's `run()` method. - Adds `Eth Watch` implementation, i. e. `EthWatchLayer` and `EthWatchTask`, in the same way it was done for `StateKeeper ` [here](https://github.com/matter-labs/zksync-era/pull/1043/files#diff-8ff8babf7b83c79dbf96f4998cf71d888beaeb265c7ce33192b0bb0c808f662b). Current "external" point of view for the framework(the only thing changed is that we add ` .add_eth_watch_layer()?` after `.add_state_keeper_layer()?`): ```rust fn main() -> anyhow::Result<()> { #[allow(deprecated)] // TODO (QIT-21): Use centralized configuration approach. let log_format = vlog::log_format_from_env(); let _guard = vlog::ObservabilityBuilder::new() .with_log_format(log_format) .build(); MainNodeBuilder::new() .add_pools_layer()? .add_fee_input_layer()? .add_object_store_layer()? .add_metadata_calculator_layer()? .add_state_keeper_layer()? .add_eth_watch_layer()? .add_healthcheck_layer()? .build() .run()?; Ok(()) } ``` --- Cargo.lock | 1 + core/lib/zksync_core/src/eth_watch/mod.rs | 23 +++-- core/lib/zksync_core/src/eth_watch/tests.rs | 14 +-- core/node/node_framework/Cargo.toml | 1 + .../node/node_framework/examples/main_node.rs | 14 ++- .../src/implementations/layers/eth_watch.rs | 88 +++++++++++++++++++ .../src/implementations/layers/mod.rs | 1 + .../layers/state_keeper/mod.rs | 1 + 8 files changed, 122 insertions(+), 21 deletions(-) create mode 100644 core/node/node_framework/src/implementations/layers/eth_watch.rs diff --git a/Cargo.lock b/Cargo.lock index e4c25ee5b5e6..0ed433615d7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8776,6 +8776,7 @@ dependencies = [ "tracing", "vlog", "zksync_config", + "zksync_contracts", "zksync_core", "zksync_dal", "zksync_env_config", diff --git a/core/lib/zksync_core/src/eth_watch/mod.rs b/core/lib/zksync_core/src/eth_watch/mod.rs index 845dab23177e..0f23650359ef 100644 --- a/core/lib/zksync_core/src/eth_watch/mod.rs +++ b/core/lib/zksync_core/src/eth_watch/mod.rs @@ -25,7 +25,7 @@ use self::{ metrics::{PollStage, METRICS}, }; -mod client; +pub mod client; mod event_processors; mod metrics; #[cfg(test)] @@ -45,6 +45,7 @@ pub struct EthWatch { event_processors: Vec>, last_processed_ethereum_block: u64, + pool: ConnectionPool, } impl EthWatch { @@ -52,7 +53,7 @@ impl EthWatch { diamond_proxy_address: Address, governance_contract: Option, mut client: Box, - pool: &ConnectionPool, + pool: ConnectionPool, poll_interval: Duration, ) -> Self { let mut storage = pool.access_storage_tagged("eth_watch").await.unwrap(); @@ -61,6 +62,8 @@ impl EthWatch { tracing::info!("initialized state: {:?}", state); + drop(storage); + let priority_ops_processor = PriorityOpsEventProcessor::new(state.next_expected_priority_id); let upgrades_processor = UpgradesEventProcessor::new(state.last_seen_version_id); @@ -89,6 +92,7 @@ impl EthWatch { poll_interval, event_processors, last_processed_ethereum_block: state.last_processed_ethereum_block, + pool, } } @@ -131,12 +135,9 @@ impl EthWatch { } } - pub async fn run( - &mut self, - pool: ConnectionPool, - stop_receiver: watch::Receiver, - ) -> anyhow::Result<()> { + pub async fn run(mut self, stop_receiver: watch::Receiver) -> anyhow::Result<()> { let mut timer = tokio::time::interval(self.poll_interval); + let pool = self.pool.clone(); loop { if *stop_receiver.borrow() { tracing::info!("Stop signal received, eth_watch is shutting down"); @@ -203,16 +204,14 @@ pub async fn start_eth_watch( config.confirmations_for_eth_event, ); - let mut eth_watch = EthWatch::new( + let eth_watch = EthWatch::new( diamond_proxy_addr, Some(governance.0), Box::new(eth_client), - &pool, + pool, config.poll_interval(), ) .await; - Ok(tokio::spawn(async move { - eth_watch.run(pool, stop_receiver).await - })) + Ok(tokio::spawn(eth_watch.run(stop_receiver))) } diff --git a/core/lib/zksync_core/src/eth_watch/tests.rs b/core/lib/zksync_core/src/eth_watch/tests.rs index aaa24746edd3..8d9965ef6f23 100644 --- a/core/lib/zksync_core/src/eth_watch/tests.rs +++ b/core/lib/zksync_core/src/eth_watch/tests.rs @@ -210,7 +210,7 @@ async fn test_normal_operation_l1_txs() { Address::default(), None, Box::new(client.clone()), - &connection_pool, + connection_pool.clone(), std::time::Duration::from_nanos(1), ) .await; @@ -258,7 +258,7 @@ async fn test_normal_operation_upgrades() { Address::default(), None, Box::new(client.clone()), - &connection_pool, + connection_pool.clone(), std::time::Duration::from_nanos(1), ) .await; @@ -319,7 +319,7 @@ async fn test_gap_in_upgrades() { Address::default(), None, Box::new(client.clone()), - &connection_pool, + connection_pool.clone(), std::time::Duration::from_nanos(1), ) .await; @@ -358,7 +358,7 @@ async fn test_normal_operation_governance_upgrades() { Address::default(), Some(governance_contract()), Box::new(client.clone()), - &connection_pool, + connection_pool.clone(), std::time::Duration::from_nanos(1), ) .await; @@ -420,7 +420,7 @@ async fn test_gap_in_single_batch() { Address::default(), None, Box::new(client.clone()), - &connection_pool, + connection_pool.clone(), std::time::Duration::from_nanos(1), ) .await; @@ -450,7 +450,7 @@ async fn test_gap_between_batches() { Address::default(), None, Box::new(client.clone()), - &connection_pool, + connection_pool.clone(), std::time::Duration::from_nanos(1), ) .await; @@ -485,7 +485,7 @@ async fn test_overlapping_batches() { Address::default(), None, Box::new(client.clone()), - &connection_pool, + connection_pool.clone(), std::time::Duration::from_nanos(1), ) .await; diff --git a/core/node/node_framework/Cargo.toml b/core/node/node_framework/Cargo.toml index a784ac804925..58aeddd790d3 100644 --- a/core/node/node_framework/Cargo.toml +++ b/core/node/node_framework/Cargo.toml @@ -19,6 +19,7 @@ zksync_object_store = { path = "../../lib/object_store" } zksync_core = { path = "../../lib/zksync_core" } zksync_storage = { path = "../../lib/storage" } zksync_eth_client = { path = "../../lib/eth_client" } +zksync_contracts = { path = "../../lib/contracts" } tracing = "0.1" thiserror = "1" diff --git a/core/node/node_framework/examples/main_node.rs b/core/node/node_framework/examples/main_node.rs index a6fa6a9e042e..7312c3c0ca4d 100644 --- a/core/node/node_framework/examples/main_node.rs +++ b/core/node/node_framework/examples/main_node.rs @@ -8,13 +8,14 @@ use zksync_config::{ chain::{MempoolConfig, NetworkConfig, OperationsManagerConfig, StateKeeperConfig}, ObservabilityConfig, }, - ApiConfig, ContractsConfig, DBConfig, ETHClientConfig, GasAdjusterConfig, ObjectStoreConfig, - PostgresConfig, + ApiConfig, ContractsConfig, DBConfig, ETHClientConfig, ETHWatchConfig, GasAdjusterConfig, + ObjectStoreConfig, PostgresConfig, }; use zksync_core::metadata_calculator::MetadataCalculatorConfig; use zksync_env_config::FromEnv; use zksync_node_framework::{ implementations::layers::{ + eth_watch::EthWatchLayer, fee_input::SequencerFeeInputLayer, healtcheck_server::HealthCheckLayer, metadata_calculator::MetadataCalculatorLayer, @@ -102,6 +103,14 @@ impl MainNodeBuilder { Ok(self) } + fn add_eth_watch_layer(mut self) -> anyhow::Result { + self.node.add_layer(EthWatchLayer::new( + ETHWatchConfig::from_env()?, + ContractsConfig::from_env()?, + )); + Ok(self) + } + fn add_healthcheck_layer(mut self) -> anyhow::Result { let healthcheck_config = ApiConfig::from_env()?.healthcheck; self.node.add_layer(HealthCheckLayer(healthcheck_config)); @@ -131,6 +140,7 @@ fn main() -> anyhow::Result<()> { .add_object_store_layer()? .add_metadata_calculator_layer()? .add_state_keeper_layer()? + .add_eth_watch_layer()? .add_healthcheck_layer()? .build() .run()?; diff --git a/core/node/node_framework/src/implementations/layers/eth_watch.rs b/core/node/node_framework/src/implementations/layers/eth_watch.rs new file mode 100644 index 000000000000..40d2776defd6 --- /dev/null +++ b/core/node/node_framework/src/implementations/layers/eth_watch.rs @@ -0,0 +1,88 @@ +use std::time::Duration; + +use zksync_config::{ContractsConfig, ETHWatchConfig}; +use zksync_contracts::governance_contract; +use zksync_core::eth_watch::{client::EthHttpQueryClient, EthWatch}; +use zksync_dal::ConnectionPool; +use zksync_types::{ethabi::Contract, Address}; + +use crate::{ + implementations::resources::{eth_interface::EthInterfaceResource, pools::MasterPoolResource}, + service::{ServiceContext, StopReceiver}, + task::Task, + wiring_layer::{WiringError, WiringLayer}, +}; + +#[derive(Debug)] +pub struct EthWatchLayer { + eth_watch_config: ETHWatchConfig, + contracts_config: ContractsConfig, +} + +impl EthWatchLayer { + pub fn new(eth_watch_config: ETHWatchConfig, contracts_config: ContractsConfig) -> Self { + Self { + eth_watch_config, + contracts_config, + } + } +} + +#[async_trait::async_trait] +impl WiringLayer for EthWatchLayer { + fn layer_name(&self) -> &'static str { + "eth_watch_layer" + } + + async fn wire(self: Box, mut context: ServiceContext<'_>) -> Result<(), WiringError> { + let pool_resource = context.get_resource::().await?; + let main_pool = pool_resource.get().await.unwrap(); + + let client = context.get_resource::().await?.0; + + let eth_client = EthHttpQueryClient::new( + client, + self.contracts_config.diamond_proxy_addr, + Some(self.contracts_config.governance_addr), + self.eth_watch_config.confirmations_for_eth_event, + ); + context.add_task(Box::new(EthWatchTask { + main_pool, + client: eth_client, + governance_contract: Some(governance_contract()), + diamond_proxy_address: self.contracts_config.diamond_proxy_addr, + poll_interval: self.eth_watch_config.poll_interval(), + })); + + Ok(()) + } +} + +#[derive(Debug)] +struct EthWatchTask { + main_pool: ConnectionPool, + client: EthHttpQueryClient, + governance_contract: Option, + diamond_proxy_address: Address, + poll_interval: Duration, +} + +#[async_trait::async_trait] +impl Task for EthWatchTask { + fn name(&self) -> &'static str { + "eth_watch" + } + + async fn run(self: Box, stop_receiver: StopReceiver) -> anyhow::Result<()> { + let eth_watch = EthWatch::new( + self.diamond_proxy_address, + self.governance_contract, + Box::new(self.client), + self.main_pool, + self.poll_interval, + ) + .await; + + eth_watch.run(stop_receiver.0).await + } +} diff --git a/core/node/node_framework/src/implementations/layers/mod.rs b/core/node/node_framework/src/implementations/layers/mod.rs index 3544f3b42ad8..3af0364a8c46 100644 --- a/core/node/node_framework/src/implementations/layers/mod.rs +++ b/core/node/node_framework/src/implementations/layers/mod.rs @@ -1,3 +1,4 @@ +pub mod eth_watch; pub mod fee_input; pub mod healtcheck_server; pub mod metadata_calculator; diff --git a/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs b/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs index 9c4ec87bc869..45c8449868a2 100644 --- a/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs +++ b/core/node/node_framework/src/implementations/layers/state_keeper/mod.rs @@ -56,6 +56,7 @@ impl WiringLayer for StateKeeperLayer { } } +#[derive(Debug)] struct StateKeeperTask { io: Box, batch_executor_base: Box, From 3878142bf0b2fe04179c6e5888ea2128c35b63a4 Mon Sep 17 00:00:00 2001 From: Leandro Ferrigno Date: Wed, 21 Feb 2024 18:59:17 -0300 Subject: [PATCH 022/106] Improve config files for validium --- infrastructure/zk/src/config.ts | 74 +++++++++++++++++ infrastructure/zk/src/config_constants.ts | 45 +++++++++++ infrastructure/zk/src/constants.ts | 12 --- infrastructure/zk/src/init.ts | 96 +---------------------- 4 files changed, 123 insertions(+), 104 deletions(-) create mode 100644 infrastructure/zk/src/config_constants.ts delete mode 100644 infrastructure/zk/src/constants.ts diff --git a/infrastructure/zk/src/config.ts b/infrastructure/zk/src/config.ts index 0496f1e46d35..d8f440a44026 100644 --- a/infrastructure/zk/src/config.ts +++ b/infrastructure/zk/src/config.ts @@ -1,8 +1,12 @@ import { Command } from 'commander'; import * as toml from '@iarna/toml'; import * as fs from 'fs'; +import * as config_constants from './config_constants'; import deepExtend from 'deep-extend'; +//Define config file's path that are updated depending on the running mode (Validium or Rollup) + + function loadConfigFile(path: string) { const fileContents = fs.readFileSync(path); try { @@ -92,6 +96,65 @@ function loadConfigRecursive(config: object, configPath: string, calledFrom: str deepExtend(config, overrides); } +function updateConfigFile(path: string, modeConstantValues: Record) { + let content = fs.readFileSync(path, 'utf-8'); + let lines = content.split('\n'); + let addedContent: string | undefined; + const lineIndices: Record = {}; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!line.startsWith('#')) { + const match = line.match(/([^=]+)=(.*)/); + if (match) { + const key = match[1].trim(); + lineIndices[key] = i; + } + } + } + + for (const [key, value] of Object.entries(modeConstantValues)) { + const lineIndex = lineIndices[key]; + + if (lineIndex !== undefined) { + if (value !== null) { + lines.splice(lineIndex, 1, `${key}=${value}`); + } else { + lines.splice(lineIndex, 1); + for (const [k, index] of Object.entries(lineIndices)) { + if (index > lineIndex) { + lineIndices[k] = index - 1; + } + } + } + } else { + if (value !== null) { + addedContent = `${key}=${value}\n`; + } + } + } + + content = lines.join('\n'); + + if (addedContent) { + content += addedContent; + } + + fs.writeFileSync(path, content); +} + + +function updateChainConfig(validiumMode: boolean) { + const modeConstantValues = config_constants.getChainConfigConstants(validiumMode) + updateConfigFile(config_constants.CHAIN_CONFIG_PATH, modeConstantValues); +} + +function updateEthSenderConfig(validiumMode: boolean) { + // This constant is used in validium mode and is deleted in rollup mode in order to pass the existing integration tests + const modeConstantValues = config_constants.getEthSenderConfigConstants(validiumMode); + updateConfigFile(config_constants.ETH_SENDER_PATH, modeConstantValues); +} + export function printAllConfigs(environment?: string) { const config = loadConfig(environment); console.log(`${JSON.stringify(config, null, 2)}`); @@ -112,6 +175,17 @@ export function compileConfig(environment?: string) { console.log(`Configs compiled for ${environment}`); } +// If running ValidiumMode config files should be updated and recompiled to get the right constant values +// UpdateConfig should be run on init +export function updateConfig(validiumMode: boolean) { + updateChainConfig(validiumMode); + updateEthSenderConfig(validiumMode); + compileConfig(); + let envFileContent = fs.readFileSync(process.env.ENV_FILE!).toString(); + envFileContent += `VALIDIUM_MODE=${validiumMode}\n`; + fs.writeFileSync(process.env.ENV_FILE!, envFileContent); +} + export const command = new Command('config').description('config management'); command.command('load [environment]').description('load the config for a certain environment').action(printAllConfigs); diff --git a/infrastructure/zk/src/config_constants.ts b/infrastructure/zk/src/config_constants.ts new file mode 100644 index 000000000000..4e76b1e1fd1a --- /dev/null +++ b/infrastructure/zk/src/config_constants.ts @@ -0,0 +1,45 @@ +// Include constants to be used on config files. +// Prefix ROLLUP_ or VALIDIUM_ is used to use the right constant depending on the running mode +const VALIDIUM_COMPUTE_OVERHEAD_PART: number = 1.0; +const ROLLUP_COMPUTE_OVERHEAD_PART: number = 0.0; +const VALIDIUM_PUBDATA_OVERHEAD_PART: number = 0.0; +const ROLLUP_PUBDATA_OVERHEAD_PART: number = 1.0; +const VALIDIUM_BATCH_OVERHEAD_L1_GAS: number = 1000000; +const ROLLUP_BATCH_OVERHEAD_L1_GAS: number = 800000; +const VALIDIUM_MAX_PUBDATA_PER_BATCH: number = 1000000000000; +const ROLLUP_MAX_PUBDATA_PER_BATCH: number = 100000; +const VALIDIUM_L1_GAS_PER_PUBDATA_BYTE: number = 0; +const ROLLUP_L1_GAS_PER_PUBDATA_BYTE: number = 17; +const VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Validium"'; +const ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Rollup"'; + +export const CHAIN_CONFIG_PATH = 'etc/env/base/chain.toml'; +export const ETH_SENDER_PATH = 'etc/env/base/eth_sender.toml'; + +export function getEthSenderConfigConstants(validiumMode: boolean) : Record { + return { + l1_gas_per_pubdata_byte: validiumMode + ? VALIDIUM_L1_GAS_PER_PUBDATA_BYTE + : ROLLUP_L1_GAS_PER_PUBDATA_BYTE + }; +} + +export function getChainConfigConstants(validiumMode: boolean) : Record { + return { + compute_overhead_part: validiumMode + ? VALIDIUM_COMPUTE_OVERHEAD_PART + : ROLLUP_COMPUTE_OVERHEAD_PART, + pubdata_overhead_part: validiumMode + ? VALIDIUM_PUBDATA_OVERHEAD_PART + : ROLLUP_PUBDATA_OVERHEAD_PART, + batch_overhead_l1_gas: validiumMode + ? VALIDIUM_BATCH_OVERHEAD_L1_GAS + : ROLLUP_BATCH_OVERHEAD_L1_GAS, + max_pubdata_per_batch: validiumMode + ? VALIDIUM_MAX_PUBDATA_PER_BATCH + : ROLLUP_MAX_PUBDATA_PER_BATCH, + l1_batch_commit_data_generator_mode: validiumMode + ? VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE + : ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE + }; +} \ No newline at end of file diff --git a/infrastructure/zk/src/constants.ts b/infrastructure/zk/src/constants.ts deleted file mode 100644 index 958674867b9c..000000000000 --- a/infrastructure/zk/src/constants.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const VALIDIUM_COMPUTE_OVERHEAD_PART: number = 1.0; -export const ROLLUP_COMPUTE_OVERHEAD_PART: number = 0.0; -export const VALIDIUM_PUBDATA_OVERHEAD_PART: number = 0.0; -export const ROLLUP_PUBDATA_OVERHEAD_PART: number = 1.0; -export const VALIDIUM_BATCH_OVERHEAD_L1_GAS: number = 1000000; -export const ROLLUP_BATCH_OVERHEAD_L1_GAS: number = 800000; -export const VALIDIUM_MAX_PUBDATA_PER_BATCH: number = 1000000000000; -export const ROLLUP_MAX_PUBDATA_PER_BATCH: number = 100000; -export const VALIDIUM_L1_GAS_PER_PUBDATA_BYTE: number = 0; -export const ROLLUP_L1_GAS_PER_PUBDATA_BYTE: number = 17; -export const VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Validium"'; -export const ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Rollup"'; diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index b1761d1bd61e..186165f8658a 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -14,14 +14,12 @@ import * as server from './server'; import { up } from './up'; import * as fs from 'fs'; -import * as constants from './constants'; const entry = chalk.bold.yellow; const announce = chalk.yellow; const success = chalk.green; const timestamp = chalk.grey; -const CHAIN_CONFIG_PATH = 'etc/env/base/chain.toml'; -const ETH_SENDER_PATH = 'etc/env/base/eth_sender.toml'; + export async function init(initArgs: InitArgs = DEFAULT_ARGS) { const { @@ -35,7 +33,7 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); process.env.VALIDIUM_MODE = validiumMode.toString(); - await announced('Updating mode configuration', updateConfig(validiumMode)); + await announced('Updating mode configuration', config.updateConfig(validiumMode)); if (!process.env.CI && !skipEnvSetup) { await announced('Pulling images', docker.pull()); await announced('Checking environment', checkEnv()); @@ -81,7 +79,7 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { export async function reinit(validiumMode: boolean) { process.env.VALIDIUM_MODE = validiumMode.toString(); await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - await announced('Updating mode configuration', updateConfig(validiumMode)); + await announced('Updating mode configuration', config.updateConfig(validiumMode)); await announced('Setting up containers', up()); await announced('Compiling JS packages', run.yarn()); await announced('Compile l2 contracts', compiler.compileAll()); @@ -104,7 +102,7 @@ export async function reinit(validiumMode: boolean) { export async function lightweightInit(validiumMode: boolean) { process.env.VALIDIUM_MODE = validiumMode.toString(); await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - await announced('Updating mode configuration', updateConfig(validiumMode)); + await announced('Updating mode configuration', config.updateConfig(validiumMode)); await announced(`Setting up containers`, up()); await announced('Clean rocksdb', clean('db')); await announced('Clean backups', clean('backups')); @@ -140,92 +138,6 @@ export async function submoduleUpdate() { await utils.exec('git submodule update'); } -function updateConfigFile(path: string, modeConstantValues: Record) { - let content = fs.readFileSync(path, 'utf-8'); - let lines = content.split('\n'); - let addedContent: string | undefined; - const lineIndices: Record = {}; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (!line.startsWith('#')) { - const match = line.match(/([^=]+)=(.*)/); - if (match) { - const key = match[1].trim(); - lineIndices[key] = i; - } - } - } - - for (const [key, value] of Object.entries(modeConstantValues)) { - const lineIndex = lineIndices[key]; - - if (lineIndex !== undefined) { - if (value !== null) { - lines.splice(lineIndex, 1, `${key}=${value}`); - } else { - lines.splice(lineIndex, 1); - for (const [k, index] of Object.entries(lineIndices)) { - if (index > lineIndex) { - lineIndices[k] = index - 1; - } - } - } - } else { - if (value !== null) { - addedContent = `${key}=${value}\n`; - } - } - } - - content = lines.join('\n'); - - if (addedContent) { - content += addedContent; - } - - fs.writeFileSync(path, content); -} -function updateChainConfig(validiumMode: boolean) { - const modeConstantValues = { - compute_overhead_part: validiumMode - ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART - : constants.ROLLUP_COMPUTE_OVERHEAD_PART, - pubdata_overhead_part: validiumMode - ? constants.VALIDIUM_PUBDATA_OVERHEAD_PART - : constants.ROLLUP_PUBDATA_OVERHEAD_PART, - batch_overhead_l1_gas: validiumMode - ? constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS - : constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, - max_pubdata_per_batch: validiumMode - ? constants.VALIDIUM_MAX_PUBDATA_PER_BATCH - : constants.ROLLUP_MAX_PUBDATA_PER_BATCH, - l1_batch_commit_data_generator_mode: validiumMode - ? constants.VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE - : constants.ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE - }; - updateConfigFile(CHAIN_CONFIG_PATH, modeConstantValues); -} -function updateEthSenderConfig(validiumMode: boolean) { - // This constant is used in validium mode and is deleted in rollup mode - // In order to pass the existing integration tests - const modeConstantValues = { - l1_gas_per_pubdata_byte: validiumMode - ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE - : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE - }; - updateConfigFile(ETH_SENDER_PATH, modeConstantValues); -} - -function updateConfig(validiumMode: boolean) { - updateChainConfig(validiumMode); - updateEthSenderConfig(validiumMode); - config.compileConfig(); - let envFileContent = fs.readFileSync(process.env.ENV_FILE!).toString(); - envFileContent += `VALIDIUM_MODE=${validiumMode}\n`; - fs.writeFileSync(process.env.ENV_FILE!, envFileContent); -} - async function checkEnv() { const tools = ['node', 'yarn', 'docker', 'cargo']; for (const tool of tools) { From 87172dd6a16125bb9450154f36808145d19b2518 Mon Sep 17 00:00:00 2001 From: Leandro Ferrigno Date: Wed, 21 Feb 2024 19:04:58 -0300 Subject: [PATCH 023/106] zk fmt on improving validium config files --- infrastructure/zk/src/config.ts | 4 +--- infrastructure/zk/src/config_constants.ts | 26 +++++++---------------- infrastructure/zk/src/init.ts | 1 - 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/infrastructure/zk/src/config.ts b/infrastructure/zk/src/config.ts index d8f440a44026..be8268869230 100644 --- a/infrastructure/zk/src/config.ts +++ b/infrastructure/zk/src/config.ts @@ -6,7 +6,6 @@ import deepExtend from 'deep-extend'; //Define config file's path that are updated depending on the running mode (Validium or Rollup) - function loadConfigFile(path: string) { const fileContents = fs.readFileSync(path); try { @@ -143,9 +142,8 @@ function updateConfigFile(path: string, modeConstantValues: Record { +export function getEthSenderConfigConstants(validiumMode: boolean): Record { return { - l1_gas_per_pubdata_byte: validiumMode - ? VALIDIUM_L1_GAS_PER_PUBDATA_BYTE - : ROLLUP_L1_GAS_PER_PUBDATA_BYTE + l1_gas_per_pubdata_byte: validiumMode ? VALIDIUM_L1_GAS_PER_PUBDATA_BYTE : ROLLUP_L1_GAS_PER_PUBDATA_BYTE }; } -export function getChainConfigConstants(validiumMode: boolean) : Record { +export function getChainConfigConstants(validiumMode: boolean): Record { return { - compute_overhead_part: validiumMode - ? VALIDIUM_COMPUTE_OVERHEAD_PART - : ROLLUP_COMPUTE_OVERHEAD_PART, - pubdata_overhead_part: validiumMode - ? VALIDIUM_PUBDATA_OVERHEAD_PART - : ROLLUP_PUBDATA_OVERHEAD_PART, - batch_overhead_l1_gas: validiumMode - ? VALIDIUM_BATCH_OVERHEAD_L1_GAS - : ROLLUP_BATCH_OVERHEAD_L1_GAS, - max_pubdata_per_batch: validiumMode - ? VALIDIUM_MAX_PUBDATA_PER_BATCH - : ROLLUP_MAX_PUBDATA_PER_BATCH, + compute_overhead_part: validiumMode ? VALIDIUM_COMPUTE_OVERHEAD_PART : ROLLUP_COMPUTE_OVERHEAD_PART, + pubdata_overhead_part: validiumMode ? VALIDIUM_PUBDATA_OVERHEAD_PART : ROLLUP_PUBDATA_OVERHEAD_PART, + batch_overhead_l1_gas: validiumMode ? VALIDIUM_BATCH_OVERHEAD_L1_GAS : ROLLUP_BATCH_OVERHEAD_L1_GAS, + max_pubdata_per_batch: validiumMode ? VALIDIUM_MAX_PUBDATA_PER_BATCH : ROLLUP_MAX_PUBDATA_PER_BATCH, l1_batch_commit_data_generator_mode: validiumMode ? VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE : ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE }; -} \ No newline at end of file +} diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index 186165f8658a..b55c1e4f3222 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -20,7 +20,6 @@ const announce = chalk.yellow; const success = chalk.green; const timestamp = chalk.grey; - export async function init(initArgs: InitArgs = DEFAULT_ARGS) { const { skipSubmodulesCheckout, From 6fdc0974077ac3a93c23429cae715bd66f9cda34 Mon Sep 17 00:00:00 2001 From: Leandro Ferrigno Date: Wed, 21 Feb 2024 19:13:53 -0300 Subject: [PATCH 024/106] modify comments --- infrastructure/zk/src/config.ts | 3 +-- infrastructure/zk/src/config_constants.ts | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/infrastructure/zk/src/config.ts b/infrastructure/zk/src/config.ts index be8268869230..90932df261fc 100644 --- a/infrastructure/zk/src/config.ts +++ b/infrastructure/zk/src/config.ts @@ -4,8 +4,6 @@ import * as fs from 'fs'; import * as config_constants from './config_constants'; import deepExtend from 'deep-extend'; -//Define config file's path that are updated depending on the running mode (Validium or Rollup) - function loadConfigFile(path: string) { const fileContents = fs.readFileSync(path); try { @@ -95,6 +93,7 @@ function loadConfigRecursive(config: object, configPath: string, calledFrom: str deepExtend(config, overrides); } +// Updates config file by overriding values received as param function updateConfigFile(path: string, modeConstantValues: Record) { let content = fs.readFileSync(path, 'utf-8'); let lines = content.split('\n'); diff --git a/infrastructure/zk/src/config_constants.ts b/infrastructure/zk/src/config_constants.ts index be96add43e99..88531b73bc75 100644 --- a/infrastructure/zk/src/config_constants.ts +++ b/infrastructure/zk/src/config_constants.ts @@ -13,6 +13,7 @@ const ROLLUP_L1_GAS_PER_PUBDATA_BYTE: number = 17; const VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Validium"'; const ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Rollup"'; +//Define config file's path that are updated depending on the running mode (Validium or Rollup) export const CHAIN_CONFIG_PATH = 'etc/env/base/chain.toml'; export const ETH_SENDER_PATH = 'etc/env/base/eth_sender.toml'; From a879621028f05578b10352bed2566e85f588f5c1 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 22 Feb 2024 17:10:56 +1100 Subject: [PATCH 025/106] chore: fix MIT license link (#1195) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ https://opensource.org/license/mit/ -> https://opensource.org/blog/license/mit/ ## Why ❔ CI is broken, seems like https://opensource.org changed the base URL for the license pages ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [x] Linkcheck has been run via `zk linkcheck`. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8cd8882de45..478f26890512 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ The following questions will be answered by the following resources: zkSync Era is distributed under the terms of either - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) -- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. From b486d7efead7afccedff9e21c98c30fb70eca66b Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 22 Feb 2024 20:20:33 +1100 Subject: [PATCH 026/106] feat(api): add a config flag for disabling filter api (#1078) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Added a config flag to disable all filter-related methods. If turned on, they report that the method is not implemented. ## Why ❔ If a node is behind a load balancer then there is no way for client to reliably hit the same node where he/she created the filter. Hence supporting this is a very awkward UX. Making this a flag since external nodes might want to turn this on if they only have a single node mapped to a static address. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [x] Tests for the changes have been added / updated. - [x] Documentation comments have been added / updated. - [x] Code has been formatted via `zk fmt` and `zk lint`. - [x] Spellcheck has been run via `zk spellcheck`. - [x] Linkcheck has been run via `zk linkcheck`. --- checks-config/era.dic | 1 + core/bin/external_node/src/config/mod.rs | 10 +++ core/bin/external_node/src/config/tests.rs | 2 + core/lib/config/src/configs/api.rs | 10 +++ core/lib/config/src/testonly.rs | 1 + core/lib/env_config/src/api.rs | 2 + core/lib/protobuf_config/src/api.rs | 2 + core/lib/protobuf_config/src/proto/api.proto | 1 + .../web3/backend_jsonrpsee/namespaces/eth.rs | 8 ++- .../zksync_core/src/api_server/web3/mod.rs | 18 +++++- .../src/api_server/web3/namespaces/eth.rs | 61 +++++++++++-------- .../zksync_core/src/api_server/web3/state.rs | 4 +- .../src/api_server/web3/tests/filters.rs | 40 ++++++++++++ .../src/api_server/web3/tests/mod.rs | 24 +++++--- .../src/api_server/web3/tests/ws.rs | 5 +- core/lib/zksync_core/src/sync_layer/tests.rs | 12 +++- etc/env/base/api.toml | 1 + 17 files changed, 160 insertions(+), 42 deletions(-) diff --git a/checks-config/era.dic b/checks-config/era.dic index 6ee220430876..36256d8e34a7 100644 --- a/checks-config/era.dic +++ b/checks-config/era.dic @@ -902,3 +902,4 @@ reimplementation composability md5 shivini +balancer \ No newline at end of file diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index 69b2f6082f99..266761310e61 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -141,6 +141,15 @@ pub struct OptionalENConfig { latest_values_cache_size_mb: usize, /// Enabled JSON RPC API namespaces. api_namespaces: Option>, + /// Whether to support methods installing filters and querying filter changes. + /// + /// When to set this value to `true`: + /// Filters are local to the specific node they were created at. Meaning if + /// there are multiple nodes behind a load balancer the client cannot reliably + /// query the previously created filter as the request might get routed to a + /// different node. + #[serde(default)] + pub filters_disabled: bool, // Gas estimation config /// The factor by which to scale the gasLimit @@ -567,6 +576,7 @@ impl From for InternalApiConfig { l2_testnet_paymaster_addr: config.remote.l2_testnet_paymaster_addr, req_entities_limit: config.optional.req_entities_limit, fee_history_limit: config.optional.fee_history_limit, + filters_disabled: config.optional.filters_disabled, } } } diff --git a/core/bin/external_node/src/config/tests.rs b/core/bin/external_node/src/config/tests.rs index 243be39a1139..57dcfe1bd51b 100644 --- a/core/bin/external_node/src/config/tests.rs +++ b/core/bin/external_node/src/config/tests.rs @@ -30,6 +30,7 @@ fn parsing_optional_config_from_empty_env() { #[test] fn parsing_optional_config_from_env() { let env_vars = [ + ("EN_FILTERS_DISABLED", "true"), ("EN_FILTERS_LIMIT", "5000"), ("EN_SUBSCRIPTIONS_LIMIT", "20000"), ("EN_FEE_HISTORY_LIMIT", "1000"), @@ -50,6 +51,7 @@ fn parsing_optional_config_from_env() { .map(|(name, value)| (name.to_owned(), value.to_owned())); let config: OptionalENConfig = envy::prefixed("EN_").from_iter(env_vars).unwrap(); + assert!(config.filters_disabled); assert_eq!(config.filters_limit, 5_000); assert_eq!(config.subscriptions_limit, 20_000); assert_eq!(config.fee_history_limit, 1_000); diff --git a/core/lib/config/src/configs/api.rs b/core/lib/config/src/configs/api.rs index a06b9fa53dfe..7e71a91b1264 100644 --- a/core/lib/config/src/configs/api.rs +++ b/core/lib/config/src/configs/api.rs @@ -32,6 +32,15 @@ pub struct Web3JsonRpcConfig { pub ws_url: String, /// Max possible limit of entities to be requested once. pub req_entities_limit: Option, + /// Whether to support methods installing filters and querying filter changes. + /// + /// When to set this value to `true`: + /// Filters are local to the specific node they were created at. Meaning if + /// there are multiple nodes behind a load balancer the client cannot reliably + /// query the previously created filter as the request might get routed to a + /// different node. + #[serde(default)] + pub filters_disabled: bool, /// Max possible limit of filters to be in the state at once. pub filters_limit: Option, /// Max possible limit of subscriptions to be in the state at once. @@ -100,6 +109,7 @@ impl Web3JsonRpcConfig { ws_port: 3051, ws_url: "ws://localhost:3051".into(), req_entities_limit: Some(10000), + filters_disabled: false, filters_limit: Some(10000), subscriptions_limit: Some(10000), pubsub_polling_interval: Some(200), diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 065e1b3e6054..46e7f0694669 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -182,6 +182,7 @@ impl RandomConfig for configs::api::Web3JsonRpcConfig { ws_port: g.gen(), ws_url: g.gen(), req_entities_limit: g.gen(), + filters_disabled: g.gen(), filters_limit: g.gen(), subscriptions_limit: g.gen(), pubsub_polling_interval: g.gen(), diff --git a/core/lib/env_config/src/api.rs b/core/lib/env_config/src/api.rs index 5368122437ff..36fa0b533b16 100644 --- a/core/lib/env_config/src/api.rs +++ b/core/lib/env_config/src/api.rs @@ -63,6 +63,7 @@ mod tests { ws_port: 3051, ws_url: "ws://127.0.0.1:3051".into(), req_entities_limit: Some(10000), + filters_disabled: false, filters_limit: Some(10000), subscriptions_limit: Some(10000), pubsub_polling_interval: Some(200), @@ -111,6 +112,7 @@ mod tests { API_WEB3_JSON_RPC_WS_PORT="3051" API_WEB3_JSON_RPC_WS_URL="ws://127.0.0.1:3051" API_WEB3_JSON_RPC_REQ_ENTITIES_LIMIT=10000 + API_WEB3_JSON_RPC_FILTERS_DISABLED=false API_WEB3_JSON_RPC_FILTERS_LIMIT=10000 API_WEB3_JSON_RPC_SUBSCRIPTIONS_LIMIT=10000 API_WEB3_JSON_RPC_PUBSUB_POLLING_INTERVAL=200 diff --git a/core/lib/protobuf_config/src/api.rs b/core/lib/protobuf_config/src/api.rs index 26173de29ff0..9a0980d1cee2 100644 --- a/core/lib/protobuf_config/src/api.rs +++ b/core/lib/protobuf_config/src/api.rs @@ -44,6 +44,7 @@ impl ProtoRepr for proto::Web3JsonRpc { .context("ws_port")?, ws_url: required(&self.ws_url).context("ws_url")?.clone(), req_entities_limit: self.req_entities_limit, + filters_disabled: self.filters_disabled.unwrap_or(false), filters_limit: self.filters_limit, subscriptions_limit: self.subscriptions_limit, pubsub_polling_interval: self.pubsub_polling_interval, @@ -128,6 +129,7 @@ impl ProtoRepr for proto::Web3JsonRpc { ws_port: Some(this.ws_port.into()), ws_url: Some(this.ws_url.clone()), req_entities_limit: this.req_entities_limit, + filters_disabled: Some(this.filters_disabled), filters_limit: this.filters_limit, subscriptions_limit: this.subscriptions_limit, pubsub_polling_interval: this.pubsub_polling_interval, diff --git a/core/lib/protobuf_config/src/proto/api.proto b/core/lib/protobuf_config/src/proto/api.proto index ce13e45d3656..8e72b7519c2a 100644 --- a/core/lib/protobuf_config/src/proto/api.proto +++ b/core/lib/protobuf_config/src/proto/api.proto @@ -35,6 +35,7 @@ message Web3JsonRpc { optional uint64 max_response_body_size_mb = 24; // optional; MB optional uint32 websocket_requests_per_minute_limit = 25; // optional optional string tree_api_url = 26; // optional + optional bool filters_disabled = 27; // optional } message ContractVerificationApi { diff --git a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs index 17256c50fe48..d3e0db24d626 100644 --- a/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs +++ b/core/lib/zksync_core/src/api_server/web3/backend_jsonrpsee/namespaces/eth.rs @@ -50,11 +50,15 @@ impl EthNamespaceServer for EthNamespace { } async fn uninstall_filter(&self, idx: U256) -> RpcResult { - Ok(self.uninstall_filter_impl(idx).await) + self.uninstall_filter_impl(idx) + .await + .map_err(into_jsrpc_error) } async fn new_pending_transaction_filter(&self) -> RpcResult { - Ok(self.new_pending_transaction_filter_impl().await) + self.new_pending_transaction_filter_impl() + .await + .map_err(into_jsrpc_error) } async fn get_logs(&self, filter: Filter) -> RpcResult> { diff --git a/core/lib/zksync_core/src/api_server/web3/mod.rs b/core/lib/zksync_core/src/api_server/web3/mod.rs index 97eeb790c316..2e007d946734 100644 --- a/core/lib/zksync_core/src/api_server/web3/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/mod.rs @@ -283,8 +283,16 @@ impl FullApiParams { let start_info = BlockStartInfo::new(&mut storage).await?; drop(storage); + let installed_filters = if self.config.filters_disabled { + None + } else { + Some(Arc::new(Mutex::new(Filters::new( + self.optional.filters_limit, + )))) + }; + Ok(RpcState { - installed_filters: Arc::new(Mutex::new(Filters::new(self.optional.filters_limit))), + installed_filters, connection_pool: self.pool, tx_sender: self.tx_sender, sync_state: self.optional.sync_state, @@ -349,7 +357,13 @@ impl FullApiParams { self, stop_receiver: watch::Receiver, ) -> anyhow::Result { - if self.optional.filters_limit.is_none() { + if self.config.filters_disabled { + if self.optional.filters_limit.is_some() { + tracing::warn!( + "Filters limit is not supported when filters are disabled, ignoring" + ); + } + } else if self.optional.filters_limit.is_none() { tracing::warn!("Filters limit is not set - unlimited filters are allowed"); } diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs index 5ffbabf834d7..76780075f036 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs @@ -231,13 +231,13 @@ impl EthNamespace { const METHOD_NAME: &str = "get_filter_logs"; let method_latency = API_METRICS.start_call(METHOD_NAME); - // We clone the filter to not hold the filter lock for an extended period of time. - let maybe_filter = self + let installed_filters = self .state .installed_filters - .lock() - .await - .get_and_update_stats(idx); + .as_ref() + .ok_or(Web3Error::NotImplemented)?; + // We clone the filter to not hold the filter lock for an extended period of time. + let maybe_filter = installed_filters.lock().await.get_and_update_stats(idx); let Some(TypedFilter::Events(filter, _)) = maybe_filter else { return Err(Web3Error::FilterNotFound); @@ -583,6 +583,11 @@ impl EthNamespace { const METHOD_NAME: &str = "new_block_filter"; let method_latency = API_METRICS.start_call(METHOD_NAME); + let installed_filters = self + .state + .installed_filters + .as_ref() + .ok_or(Web3Error::NotImplemented)?; let mut storage = self .state .connection_pool @@ -598,9 +603,7 @@ impl EthNamespace { let next_block_number = last_block_number + 1; drop(storage); - let idx = self - .state - .installed_filters + let idx = installed_filters .lock() .await .add(TypedFilter::Blocks(next_block_number)); @@ -613,6 +616,11 @@ impl EthNamespace { const METHOD_NAME: &str = "new_filter"; let method_latency = API_METRICS.start_call(METHOD_NAME); + let installed_filters = self + .state + .installed_filters + .as_ref() + .ok_or(Web3Error::NotImplemented)?; if let Some(topics) = filter.topics.as_ref() { if topics.len() > EVENT_TOPIC_NUMBER_LIMIT { return Err(Web3Error::TooManyTopics); @@ -621,9 +629,7 @@ impl EthNamespace { self.state.resolve_filter_block_hash(&mut filter).await?; let from_block = self.state.get_filter_from_block(&filter).await?; - let idx = self - .state - .installed_filters + let idx = installed_filters .lock() .await .add(TypedFilter::Events(filter, from_block)); @@ -632,20 +638,23 @@ impl EthNamespace { } #[tracing::instrument(skip(self))] - pub async fn new_pending_transaction_filter_impl(&self) -> U256 { + pub async fn new_pending_transaction_filter_impl(&self) -> Result { const METHOD_NAME: &str = "new_pending_transaction_filter"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let idx = self + let installed_filters = self .state .installed_filters + .as_ref() + .ok_or(Web3Error::NotImplemented)?; + let idx = installed_filters .lock() .await .add(TypedFilter::PendingTransactions( chrono::Utc::now().naive_utc(), )); method_latency.observe(); - idx + Ok(idx) } #[tracing::instrument(skip(self))] @@ -653,9 +662,12 @@ impl EthNamespace { const METHOD_NAME: &str = "get_filter_changes"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let mut filter = self + let installed_filters = self .state .installed_filters + .as_ref() + .ok_or(Web3Error::NotImplemented)?; + let mut filter = installed_filters .lock() .await .get_and_update_stats(idx) @@ -663,16 +675,12 @@ impl EthNamespace { let result = match self.filter_changes(&mut filter).await { Ok(changes) => { - self.state - .installed_filters - .lock() - .await - .update(idx, filter); + installed_filters.lock().await.update(idx, filter); Ok(changes) } Err(Web3Error::LogsLimitExceeded(..)) => { // The filter was not being polled for a long time, so we remove it. - self.state.installed_filters.lock().await.remove(idx); + installed_filters.lock().await.remove(idx); Err(Web3Error::FilterNotFound) } Err(err) => Err(err), @@ -682,13 +690,18 @@ impl EthNamespace { } #[tracing::instrument(skip(self))] - pub async fn uninstall_filter_impl(&self, idx: U256) -> bool { + pub async fn uninstall_filter_impl(&self, idx: U256) -> Result { const METHOD_NAME: &str = "uninstall_filter"; let method_latency = API_METRICS.start_call(METHOD_NAME); - let removed = self.state.installed_filters.lock().await.remove(idx); + let installed_filters = self + .state + .installed_filters + .as_ref() + .ok_or(Web3Error::NotImplemented)?; + let removed = installed_filters.lock().await.remove(idx); method_latency.observe(); - removed + Ok(removed) } #[tracing::instrument(skip(self))] diff --git a/core/lib/zksync_core/src/api_server/web3/state.rs b/core/lib/zksync_core/src/api_server/web3/state.rs index 6620d1d664bf..be17f5bb4275 100644 --- a/core/lib/zksync_core/src/api_server/web3/state.rs +++ b/core/lib/zksync_core/src/api_server/web3/state.rs @@ -86,6 +86,7 @@ pub struct InternalApiConfig { pub l2_testnet_paymaster_addr: Option

    , pub req_entities_limit: usize, pub fee_history_limit: u64, + pub filters_disabled: bool, } impl InternalApiConfig { @@ -112,6 +113,7 @@ impl InternalApiConfig { l2_testnet_paymaster_addr: contracts_config.l2_testnet_paymaster_addr, req_entities_limit: web3_config.req_entities_limit(), fee_history_limit: web3_config.fee_history_limit(), + filters_disabled: web3_config.filters_disabled, } } } @@ -194,7 +196,7 @@ impl SealedMiniblockNumber { /// Holder for the data required for the API to be functional. #[derive(Debug, Clone)] pub struct RpcState { - pub(crate) installed_filters: Arc>, + pub(crate) installed_filters: Option>>, pub connection_pool: ConnectionPool, pub tree_api: Option, pub tx_sender: TxSender, diff --git a/core/lib/zksync_core/src/api_server/web3/tests/filters.rs b/core/lib/zksync_core/src/api_server/web3/tests/filters.rs index 1321b7241b64..76337be9f693 100644 --- a/core/lib/zksync_core/src/api_server/web3/tests/filters.rs +++ b/core/lib/zksync_core/src/api_server/web3/tests/filters.rs @@ -1,5 +1,8 @@ //! Tests for filter-related methods in the `eth` namespace. +use std::fmt::Debug; + +use jsonrpsee::{core::client::Error, types::error::ErrorCode}; use zksync_web3_decl::{jsonrpsee::core::ClientError as RpcError, types::FilterChanges}; use super::*; @@ -263,3 +266,40 @@ impl HttpTest for LogFilterChangesWithBlockBoundariesTest { async fn log_filter_changes_with_block_boundaries() { test_http_server(LogFilterChangesWithBlockBoundariesTest).await; } + +fn assert_not_implemented(result: Result) { + assert_matches!(result, Err(Error::Call(e)) => { + assert_eq!(e.code(), ErrorCode::InternalError.code()); + assert_eq!(e.message(), "Not implemented"); + }); +} + +#[derive(Debug)] +struct DisableFiltersTest; + +#[async_trait] +impl HttpTest for DisableFiltersTest { + async fn test(&self, client: &HttpClient, _pool: &ConnectionPool) -> anyhow::Result<()> { + let filter = Filter { + from_block: Some(api::BlockNumber::Number(2.into())), + ..Filter::default() + }; + assert_not_implemented(client.new_filter(filter).await); + assert_not_implemented(client.new_block_filter().await); + assert_not_implemented(client.uninstall_filter(1.into()).await); + assert_not_implemented(client.new_pending_transaction_filter().await); + assert_not_implemented(client.get_filter_logs(1.into()).await); + assert_not_implemented(client.get_filter_changes(1.into()).await); + + Ok(()) + } + + fn filters_disabled(&self) -> bool { + true + } +} + +#[tokio::test] +async fn disable_filters() { + test_http_server(DisableFiltersTest).await; +} diff --git a/core/lib/zksync_core/src/api_server/web3/tests/mod.rs b/core/lib/zksync_core/src/api_server/web3/tests/mod.rs index ca39d7693319..2ea1d677e890 100644 --- a/core/lib/zksync_core/src/api_server/web3/tests/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/tests/mod.rs @@ -100,14 +100,14 @@ impl ApiServerHandles { } pub(crate) async fn spawn_http_server( - network_config: &NetworkConfig, + api_config: InternalApiConfig, pool: ConnectionPool, tx_executor: MockTransactionExecutor, stop_receiver: watch::Receiver, ) -> ApiServerHandles { spawn_server( ApiTransportLabel::Http, - network_config, + api_config, pool, None, tx_executor, @@ -118,14 +118,14 @@ pub(crate) async fn spawn_http_server( } async fn spawn_ws_server( - network_config: &NetworkConfig, + api_config: InternalApiConfig, pool: ConnectionPool, stop_receiver: watch::Receiver, websocket_requests_per_minute_limit: Option, ) -> (ApiServerHandles, mpsc::UnboundedReceiver) { spawn_server( ApiTransportLabel::Ws, - network_config, + api_config, pool, websocket_requests_per_minute_limit, MockTransactionExecutor::default(), @@ -136,15 +136,12 @@ async fn spawn_ws_server( async fn spawn_server( transport: ApiTransportLabel, - network_config: &NetworkConfig, + api_config: InternalApiConfig, pool: ConnectionPool, websocket_requests_per_minute_limit: Option, tx_executor: MockTransactionExecutor, stop_receiver: watch::Receiver, ) -> (ApiServerHandles, mpsc::UnboundedReceiver) { - let contracts_config = ContractsConfig::for_tests(); - let web3_config = Web3JsonRpcConfig::for_tests(); - let api_config = InternalApiConfig::new(network_config, &web3_config, &contracts_config); let (tx_sender, vm_barrier) = create_test_tx_sender(pool.clone(), api_config.l2_chain_id, tx_executor.into()).await; let (pub_sub_events_sender, pub_sub_events_receiver) = mpsc::unbounded_channel(); @@ -188,6 +185,11 @@ trait HttpTest: Send + Sync { } async fn test(&self, client: &HttpClient, pool: &ConnectionPool) -> anyhow::Result<()>; + + /// Overrides the `filters_disabled` configuration parameter for HTTP server startup + fn filters_disabled(&self) -> bool { + false + } } /// Storage initialization strategy. @@ -260,8 +262,12 @@ async fn test_http_server(test: impl HttpTest) { drop(storage); let (stop_sender, stop_receiver) = watch::channel(false); + let contracts_config = ContractsConfig::for_tests(); + let web3_config = Web3JsonRpcConfig::for_tests(); + let mut api_config = InternalApiConfig::new(&network_config, &web3_config, &contracts_config); + api_config.filters_disabled = test.filters_disabled(); let mut server_handles = spawn_http_server( - &network_config, + api_config, pool.clone(), test.transaction_executor(), stop_receiver, diff --git a/core/lib/zksync_core/src/api_server/web3/tests/ws.rs b/core/lib/zksync_core/src/api_server/web3/tests/ws.rs index 8294915f2702..07846ff92595 100644 --- a/core/lib/zksync_core/src/api_server/web3/tests/ws.rs +++ b/core/lib/zksync_core/src/api_server/web3/tests/ws.rs @@ -164,6 +164,9 @@ trait WsTest: Send + Sync { async fn test_ws_server(test: impl WsTest) { let pool = ConnectionPool::test_pool().await; let network_config = NetworkConfig::for_tests(); + let contracts_config = ContractsConfig::for_tests(); + let web3_config = Web3JsonRpcConfig::for_tests(); + let api_config = InternalApiConfig::new(&network_config, &web3_config, &contracts_config); let mut storage = pool.access_storage().await.unwrap(); test.storage_initialization() .prepare_storage(&network_config, &mut storage) @@ -173,7 +176,7 @@ async fn test_ws_server(test: impl WsTest) { let (stop_sender, stop_receiver) = watch::channel(false); let (mut server_handles, pub_sub_events) = spawn_ws_server( - &network_config, + api_config, pool.clone(), stop_receiver, test.websocket_requests_per_minute_limit(), diff --git a/core/lib/zksync_core/src/sync_layer/tests.rs b/core/lib/zksync_core/src/sync_layer/tests.rs index eb4745156fc0..36aec10a9e79 100644 --- a/core/lib/zksync_core/src/sync_layer/tests.rs +++ b/core/lib/zksync_core/src/sync_layer/tests.rs @@ -9,7 +9,10 @@ use std::{ use test_casing::test_casing; use tokio::{sync::watch, task::JoinHandle}; -use zksync_config::configs::chain::NetworkConfig; +use zksync_config::{ + configs::{api::Web3JsonRpcConfig, chain::NetworkConfig}, + ContractsConfig, +}; use zksync_contracts::BaseSystemContractsHashes; use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_types::{ @@ -22,7 +25,7 @@ use zksync_types::{ use super::{sync_action::SyncAction, *}; use crate::{ - api_server::web3::tests::spawn_http_server, + api_server::web3::{state::InternalApiConfig, tests::spawn_http_server}, consensus::testonly::MockMainNodeClient, genesis::{ensure_genesis_state, GenesisParams}, state_keeper::{ @@ -677,9 +680,12 @@ async fn fetcher_with_real_server(snapshot_recovery: bool) { // Start the API server. let network_config = NetworkConfig::for_tests(); + let contracts_config = ContractsConfig::for_tests(); + let web3_config = Web3JsonRpcConfig::for_tests(); + let api_config = InternalApiConfig::new(&network_config, &web3_config, &contracts_config); let (stop_sender, stop_receiver) = watch::channel(false); let mut server_handles = spawn_http_server( - &network_config, + api_config, pool.clone(), Default::default(), stop_receiver.clone(), diff --git a/etc/env/base/api.toml b/etc/env/base/api.toml index 1c5d906603fb..61e53b9a7db5 100644 --- a/etc/env/base/api.toml +++ b/etc/env/base/api.toml @@ -10,6 +10,7 @@ http_url="http://127.0.0.1:3050" ws_port=3051 ws_url="ws://127.0.0.1:3051" req_entities_limit=10000 +filters_disabled=false filters_limit=10000 subscriptions_limit=10000 # Interval between polling db for pubsub (in ms). From b9e8836dec03a54c3906fc72e03051fef5addaf7 Mon Sep 17 00:00:00 2001 From: Jordi Date: Thu, 22 Feb 2024 11:21:15 +0100 Subject: [PATCH 027/106] Implement serde solution --- core/lib/config/src/configs/chain.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index 7a0504503c19..a1aaca3c5839 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -52,6 +52,10 @@ pub enum L1BatchCommitDataGeneratorMode { Validium, } +fn default_l1_batch_commit_data_generator_mode() -> L1BatchCommitDataGeneratorMode { + L1BatchCommitDataGeneratorMode::Rollup +} + #[derive(Debug, Deserialize, Clone, PartialEq, Default)] pub struct StateKeeperConfig { /// The max number of slots for txs in a block before it should be sealed by the slots sealer. @@ -123,7 +127,7 @@ pub struct StateKeeperConfig { /// Number of keys that is processed by enum_index migration in State Keeper each L1 batch. pub enum_index_migration_chunk_size: Option, - + #[serde(default = "default_l1_batch_commit_data_generator_mode")] pub l1_batch_commit_data_generator_mode: L1BatchCommitDataGeneratorMode, } From 3aa12e8a58699961624f7a88143133c6c2a150a0 Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Thu, 22 Feb 2024 11:35:53 +0100 Subject: [PATCH 028/106] chore(prover): small features for 4844 proofs (#1181) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Added verification key and finalization hint file for 4844 circuit * Actually start saving finalization hint when generating verification keys * Fixed witness vector generator for 4844 circuit - used by GPU prover ## Why ❔ * Necessary steps to start creating 4844 proofs --- Cargo.lock | 31 ++- prover/Cargo.lock | 4 +- .../data/eip4844_vk.json | 242 ++++++++++++++++++ .../data/finalization_hints_eip4844.bin | Bin 0 -> 200 bytes .../src/keystore.rs | 11 + .../witness_vector_generator/src/generator.rs | 31 ++- .../tests/basic_test.rs | 4 +- 7 files changed, 300 insertions(+), 23 deletions(-) create mode 100644 prover/vk_setup_data_generator_server_fri/data/eip4844_vk.json create mode 100644 prover/vk_setup_data_generator_server_fri/data/finalization_hints_eip4844.bin diff --git a/Cargo.lock b/Cargo.lock index 0ed433615d7c..e92b4bd4b23d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -906,8 +906,8 @@ dependencies = [ [[package]] name = "boojum" -version = "0.1.0" -source = "git+https://github.com/matter-labs/era-boojum.git?branch=main#93b5e0f0dbff0a9b606d9025e207c8405c141bd9" +version = "0.2.0" +source = "git+https://github.com/matter-labs/era-boojum.git?branch=main#30300f043c9afaeeb35d0f7bd3cc0acaf69ccde4" dependencies = [ "arrayvec 0.7.4", "bincode", @@ -1206,7 +1206,7 @@ dependencies = [ [[package]] name = "circuit_definitions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#de2ecad62ac8c12777e576dca20311ad8ec770d1" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#aff36380e6a740f7286c9c522e1416b8d38327ce" dependencies = [ "crossbeam 0.8.2", "derivative", @@ -1220,7 +1220,7 @@ dependencies = [ [[package]] name = "circuit_definitions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#d4e9215d4fe8f4d311e1c01a9b561e4d04cb426b" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#9a3e322268f0d06d09a419fc05d06c7139ceb847" dependencies = [ "crossbeam 0.8.2", "derivative", @@ -1710,7 +1710,7 @@ dependencies = [ [[package]] name = "cs_derive" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-boojum.git?branch=main#93b5e0f0dbff0a9b606d9025e207c8405c141bd9" +source = "git+https://github.com/matter-labs/era-boojum.git?branch=main#30300f043c9afaeeb35d0f7bd3cc0acaf69ccde4" dependencies = [ "proc-macro-error", "proc-macro2 1.0.69", @@ -5268,7 +5268,7 @@ dependencies = [ [[package]] name = "rescue_poseidon" version = "0.4.1" -source = "git+https://github.com/matter-labs/rescue-poseidon.git?branch=poseidon2#2e5e8afb152adc326fcf776a71ad3735fa7f3186" +source = "git+https://github.com/matter-labs/rescue-poseidon.git?branch=poseidon2#126937ef0e7a281f1ff9f512ac41a746a691a342" dependencies = [ "addchain", "arrayvec 0.7.4", @@ -5276,6 +5276,7 @@ dependencies = [ "byteorder", "derivative", "franklin-crypto 0.0.5 (git+https://github.com/matter-labs/franklin-crypto?branch=snark_wrapper)", + "lazy_static", "log", "num-bigint 0.3.3", "num-integer", @@ -5285,6 +5286,7 @@ dependencies = [ "serde", "sha3 0.9.1", "smallvec", + "typemap_rev", ] [[package]] @@ -6150,7 +6152,7 @@ dependencies = [ [[package]] name = "snark_wrapper" version = "0.1.0" -source = "git+https://github.com/matter-labs/snark-wrapper.git?branch=main#42661a9ff9d00853441589679c101f71e3785f55" +source = "git+https://github.com/matter-labs/snark-wrapper.git?branch=main#76959cadabeec344b9fa1458728400d60340e496" dependencies = [ "derivative", "rand 0.4.6", @@ -7169,6 +7171,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typemap_rev" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" + [[package]] name = "typenum" version = "1.17.0" @@ -8047,7 +8055,7 @@ dependencies = [ [[package]] name = "zkevm_circuits" version = "1.4.0" -source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=main#4fba537ccecc238e2da9c80844dc8c185e42466f" +source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=main#fb3e2574b5c890342518fc930c145443f039a105" dependencies = [ "arrayvec 0.7.4", "bincode", @@ -8058,6 +8066,7 @@ dependencies = [ "itertools 0.10.5", "rand 0.4.6", "rand 0.8.5", + "seq-macro", "serde", "serde_json", "smallvec", @@ -8067,7 +8076,7 @@ dependencies = [ [[package]] name = "zkevm_circuits" version = "1.4.1" -source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.4.1#873fe0fcf0bb8df6be0ae1938ce8469d6bf63ebd" +source = "git+https://github.com/matter-labs/era-zkevm_circuits.git?branch=v1.4.1#3a973afb3cf2b50b7138c1af61cc6ac3d7d0189f" dependencies = [ "arrayvec 0.7.4", "bincode", @@ -8154,7 +8163,7 @@ dependencies = [ [[package]] name = "zkevm_test_harness" version = "1.4.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#de2ecad62ac8c12777e576dca20311ad8ec770d1" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0#aff36380e6a740f7286c9c522e1416b8d38327ce" dependencies = [ "bincode", "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.0)", @@ -8177,7 +8186,7 @@ dependencies = [ [[package]] name = "zkevm_test_harness" version = "1.4.1" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#d4e9215d4fe8f4d311e1c01a9b561e4d04cb426b" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#9a3e322268f0d06d09a419fc05d06c7139ceb847" dependencies = [ "bincode", "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 0ce09698ef4c..6b6d001c7547 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -808,7 +808,7 @@ dependencies = [ [[package]] name = "circuit_definitions" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#577f3d73f8c2e9c4cb8fe30f16672af66550af9f" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#9a3e322268f0d06d09a419fc05d06c7139ceb847" dependencies = [ "crossbeam 0.8.4", "derivative", @@ -6831,7 +6831,7 @@ dependencies = [ [[package]] name = "zkevm_test_harness" version = "1.4.1" -source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#577f3d73f8c2e9c4cb8fe30f16672af66550af9f" +source = "git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1#9a3e322268f0d06d09a419fc05d06c7139ceb847" dependencies = [ "bincode", "circuit_definitions 0.1.0 (git+https://github.com/matter-labs/era-zkevm_test_harness.git?branch=v1.4.1)", diff --git a/prover/vk_setup_data_generator_server_fri/data/eip4844_vk.json b/prover/vk_setup_data_generator_server_fri/data/eip4844_vk.json new file mode 100644 index 000000000000..39c15a71a9d2 --- /dev/null +++ b/prover/vk_setup_data_generator_server_fri/data/eip4844_vk.json @@ -0,0 +1,242 @@ +{ + "fixed_parameters": { + "parameters": { + "num_columns_under_copy_permutation": 60, + "num_witness_columns": 0, + "num_constant_columns": 8, + "max_allowed_constraint_degree": 4 + }, + "lookup_parameters": { + "UseSpecializedColumnsWithTableIdAsConstant": { + "width": 3, + "num_repetitions": 20, + "share_table_id": true + } + }, + "domain_size": 1048576, + "total_tables_len": 132096, + "public_inputs_locations": [ + [ + 0, + 871888 + ], + [ + 1, + 871888 + ], + [ + 2, + 871888 + ], + [ + 3, + 871888 + ] + ], + "extra_constant_polys_for_selectors": 2, + "table_ids_column_idxes": [ + 10 + ], + "quotient_degree": 8, + "selectors_placement": { + "Fork": { + "left": { + "Fork": { + "left": { + "Fork": { + "left": { + "Fork": { + "left": { + "Fork": { + "left": { + "GateOnly": { + "gate_idx": 2, + "num_constants": 2, + "degree": 3, + "needs_selector": true, + "is_lookup": false + } + }, + "right": { + "Fork": { + "left": { + "GateOnly": { + "gate_idx": 7, + "num_constants": 0, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + }, + "right": { + "GateOnly": { + "gate_idx": 1, + "num_constants": 0, + "degree": 0, + "needs_selector": true, + "is_lookup": false + } + } + } + } + } + }, + "right": { + "GateOnly": { + "gate_idx": 6, + "num_constants": 0, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + } + } + }, + "right": { + "GateOnly": { + "gate_idx": 4, + "num_constants": 0, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + } + } + }, + "right": { + "GateOnly": { + "gate_idx": 5, + "num_constants": 1, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + } + } + }, + "right": { + "Fork": { + "left": { + "GateOnly": { + "gate_idx": 3, + "num_constants": 4, + "degree": 2, + "needs_selector": true, + "is_lookup": false + } + }, + "right": { + "GateOnly": { + "gate_idx": 0, + "num_constants": 8, + "degree": 1, + "needs_selector": true, + "is_lookup": false + } + } + } + } + } + }, + "fri_lde_factor": 2, + "cap_size": 16 + }, + "setup_merkle_tree_cap": [ + [ + 15012885272458350464, + 12918123785161914480, + 13671686572559106862, + 458420429559950553 + ], + [ + 3855596161956112429, + 9367986999640085982, + 9576686990164770909, + 15736630811802716592 + ], + [ + 4429424595585567228, + 1726575003907041811, + 11808623125777752326, + 7960090163308302001 + ], + [ + 16198073096358255703, + 1773566633554043329, + 15852741538281887312, + 3672365904403393548 + ], + [ + 5014302247141995239, + 15298901224361045295, + 17058410652708079000, + 2451098419087154466 + ], + [ + 1883879201519384194, + 16513689436046407106, + 18106823921911623646, + 12195558529156429070 + ], + [ + 3553190024094472044, + 16085740316966804610, + 7469059494943248345, + 8466978240947973162 + ], + [ + 15733255750285479223, + 10035744743646423118, + 12893682562633909811, + 17018145047346847928 + ], + [ + 4190189918857924629, + 11079126332194735217, + 81863766911265321, + 1252088896597638701 + ], + [ + 13713450655978854074, + 6658527377300991599, + 11379765760362527623, + 18157417093208935759 + ], + [ + 13291575128912167224, + 5612545196785048171, + 14736834588908638980, + 3368626854973932908 + ], + [ + 6550473513308471355, + 261602743346828260, + 3476562827380596578, + 16103482668860064473 + ], + [ + 3000784508673768350, + 1118466443868787057, + 13001376126891710198, + 5277667505560256643 + ], + [ + 1638204738185533106, + 2943638319874219165, + 37345818451115499, + 6602609125606041803 + ], + [ + 8835198552893947573, + 13366615065126505958, + 15913885131147312037, + 11776601604937573132 + ], + [ + 12125147286940007597, + 9198361601962582562, + 9157325123238861992, + 14770289666410955142 + ] + ] +} \ No newline at end of file diff --git a/prover/vk_setup_data_generator_server_fri/data/finalization_hints_eip4844.bin b/prover/vk_setup_data_generator_server_fri/data/finalization_hints_eip4844.bin new file mode 100644 index 0000000000000000000000000000000000000000..3abbc382b036b708fe89a2669751be53abc332a5 GIT binary patch literal 200 zcmZQzfB;4)9Ra1;(8NJpCa4&QVg_O!D4zw1&5FbZnZW^7b08I>T7MJF6aladNG~$D W;L8ihs@CSDQ literal 0 HcmV?d00001 diff --git a/prover/vk_setup_data_generator_server_fri/src/keystore.rs b/prover/vk_setup_data_generator_server_fri/src/keystore.rs index ccb729a1cf1c..3b6e29f2684c 100644 --- a/prover/vk_setup_data_generator_server_fri/src/keystore.rs +++ b/prover/vk_setup_data_generator_server_fri/src/keystore.rs @@ -336,6 +336,10 @@ impl Keystore { ZkSyncRecursionLayerStorageType::NodeLayerCircuit as u8, )?) .unwrap(); + + data_source + .set_eip4844_vk(self.load_4844_verification_key()?) + .unwrap(); Ok(data_source) } @@ -441,6 +445,13 @@ impl Keystore { ) .context("save_4844_verification_key()")?; + let eip4844_hint = source.get_eip4844_finalization_hint().map_err(|err| { + anyhow::anyhow!("No finalization hint exist for scheduler layer circuit: {err}") + })?; + + self.save_finalization_hints(ProverServiceDataKey::eip4844(), &eip4844_hint) + .context("save_eip4844_hint()")?; + Ok(()) } } diff --git a/prover/witness_vector_generator/src/generator.rs b/prover/witness_vector_generator/src/generator.rs index 3b49433dfdde..0dda842a2f2f 100644 --- a/prover/witness_vector_generator/src/generator.rs +++ b/prover/witness_vector_generator/src/generator.rs @@ -11,8 +11,15 @@ use zksync_config::configs::FriWitnessVectorGeneratorConfig; use zksync_dal::{fri_prover_dal::types::GpuProverInstanceStatus, ConnectionPool}; use zksync_object_store::ObjectStore; use zksync_prover_fri_types::{ - circuit_definitions::boojum::field::goldilocks::GoldilocksField, CircuitWrapper, ProverJob, - WitnessVectorArtifacts, + circuit_definitions::{ + boojum::{ + config::{CSConfig, ProvingCSConfig}, + dag::StCircuitResolver, + field::goldilocks::GoldilocksField, + }, + circuit_definitions::eip4844::synthesis, + }, + CircuitWrapper, ProverJob, WitnessVectorArtifacts, }; use zksync_prover_fri_utils::{ fetch_next_circuit, get_numeric_circuit_id, socket_utils::send_assembly, @@ -54,8 +61,10 @@ impl WitnessVectorGenerator { } } - pub fn generate_witness_vector(job: ProverJob) -> anyhow::Result { - let keystore = Keystore::default(); + pub fn generate_witness_vector( + job: ProverJob, + keystore: &Keystore, + ) -> anyhow::Result { let finalization_hints = keystore .load_finalization_hints(job.setup_data_key.clone()) .context("get_finalization_hints()")?; @@ -66,10 +75,12 @@ impl WitnessVectorGenerator { CircuitWrapper::Recursive(recursive_circuit) => { recursive_circuit.synthesis::(&finalization_hints) } - CircuitWrapper::Eip4844(_) => { - // TODO: figure out if we support 4844 circuit as GPU. - todo!() - } + CircuitWrapper::Eip4844(circuit) => synthesis::< + _, + _, + _, + StCircuitResolver::ResolverConfig>, + >(circuit, &finalization_hints), }; Ok(WitnessVectorArtifacts::new(cs.witness.unwrap(), job)) } @@ -114,7 +125,9 @@ impl JobProcessor for WitnessVectorGenerator { job: ProverJob, _started_at: Instant, ) -> JoinHandle> { - tokio::task::spawn_blocking(move || Self::generate_witness_vector(job)) + tokio::task::spawn_blocking(move || { + Self::generate_witness_vector(job, &Keystore::default()) + }) } async fn save_result( diff --git a/prover/witness_vector_generator/tests/basic_test.rs b/prover/witness_vector_generator/tests/basic_test.rs index 54898cf94d5d..9c014697ad3a 100644 --- a/prover/witness_vector_generator/tests/basic_test.rs +++ b/prover/witness_vector_generator/tests/basic_test.rs @@ -2,6 +2,7 @@ use std::fs; use zksync_prover_fri_types::{CircuitWrapper, ProverJob, ProverServiceDataKey}; use zksync_types::{basic_fri_types::AggregationRound, L1BatchNumber}; +use zksync_vk_setup_data_server_fri::keystore::Keystore; use zksync_witness_vector_generator::generator::WitnessVectorGenerator; #[test] @@ -20,7 +21,8 @@ fn test_generate_witness_vector() { circuit_wrapper, setup_data_key: key, }; - let vector = WitnessVectorGenerator::generate_witness_vector(job).unwrap(); + let vector = + WitnessVectorGenerator::generate_witness_vector(job, &Keystore::default()).unwrap(); assert!(!vector.witness_vector.all_values.is_empty()); assert!(!vector.witness_vector.multiplicities.is_empty()); assert!(!vector.witness_vector.public_inputs_locations.is_empty()); From ecb41186e3e72522f378c18352becdeff8f96c02 Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Thu, 22 Feb 2024 13:53:28 +0200 Subject: [PATCH 029/106] refactor(state-keeper): Propagate I/O errors in state keeper (#1080) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ - Propagates I/O errors in the state keeper using `anyhow::Result`, adding context to calls where appropriate. - Propagates DB errors in `FactoryDepsDal`. ## Why ❔ Propagating errors makes it easier to attach additional context to them; thus, it improves DevEx and code maintainability. ## Checklist - [x] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [x] Tests for the changes have been added / updated. - [x] Documentation comments have been added / updated. - [x] Code has been formatted via `zk fmt` and `zk lint`. - [x] Spellcheck has been run via `zk spellcheck`. - [x] Linkcheck has been run via `zk linkcheck`. --- core/lib/dal/src/factory_deps_dal.rs | 33 ++-- core/lib/dal/src/protocol_versions_dal.rs | 40 ++-- core/lib/vm_utils/src/storage.rs | 3 +- .../src/api_server/web3/namespaces/zks.rs | 7 +- .../lib/zksync_core/src/block_reverter/mod.rs | 5 +- .../state_keeper/io/fee_address_migration.rs | 11 +- .../src/state_keeper/io/mempool.rs | 125 +++++------- .../zksync_core/src/state_keeper/io/mod.rs | 27 ++- .../src/state_keeper/io/tests/mod.rs | 21 +- .../zksync_core/src/state_keeper/keeper.rs | 96 ++++++---- .../src/state_keeper/tests/tester.rs | 27 +-- .../zksync_core/src/sync_layer/external_io.rs | 179 ++++++++++-------- .../witness_generator/src/basic_circuits.rs | 4 +- 13 files changed, 312 insertions(+), 266 deletions(-) diff --git a/core/lib/dal/src/factory_deps_dal.rs b/core/lib/dal/src/factory_deps_dal.rs index a23eb706f6b5..bb5f2937c18d 100644 --- a/core/lib/dal/src/factory_deps_dal.rs +++ b/core/lib/dal/src/factory_deps_dal.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; +use anyhow::Context as _; use zksync_contracts::{BaseSystemContracts, SystemContractCode}; use zksync_types::{MiniblockNumber, H256, U256}; use zksync_utils::{bytes_to_be_words, bytes_to_chunks}; @@ -22,7 +23,7 @@ impl FactoryDepsDal<'_, '_> { ) -> sqlx::Result<()> { let (bytecode_hashes, bytecodes): (Vec<_>, Vec<_>) = factory_deps .iter() - .map(|dep| (dep.0.as_bytes(), dep.1.as_slice())) + .map(|(hash, bytecode)| (hash.as_bytes(), bytecode.as_slice())) .unzip(); // Copy from stdin can't be used here because of `ON CONFLICT`. @@ -51,8 +52,8 @@ impl FactoryDepsDal<'_, '_> { } /// Returns bytecode for a factory dependency with the specified bytecode `hash`. - pub async fn get_factory_dep(&mut self, hash: H256) -> Option> { - sqlx::query!( + pub async fn get_factory_dep(&mut self, hash: H256) -> sqlx::Result>> { + Ok(sqlx::query!( r#" SELECT bytecode @@ -64,20 +65,20 @@ impl FactoryDepsDal<'_, '_> { hash.as_bytes(), ) .fetch_optional(self.storage.conn()) - .await - .unwrap() - .map(|row| row.bytecode) + .await? + .map(|row| row.bytecode)) } pub async fn get_base_system_contracts( &mut self, bootloader_hash: H256, default_aa_hash: H256, - ) -> BaseSystemContracts { + ) -> anyhow::Result { let bootloader_bytecode = self .get_factory_dep(bootloader_hash) .await - .expect("Bootloader code should be present in the database"); + .context("failed loading bootloader code")? + .with_context(|| format!("bootloader code with hash {bootloader_hash:?} should be present in the database"))?; let bootloader_code = SystemContractCode { code: bytes_to_be_words(bootloader_bytecode), hash: bootloader_hash, @@ -86,16 +87,17 @@ impl FactoryDepsDal<'_, '_> { let default_aa_bytecode = self .get_factory_dep(default_aa_hash) .await - .expect("Default account code should be present in the database"); + .context("failed loading default account code")? + .with_context(|| format!("default account code with hash {default_aa_hash:?} should be present in the database"))?; let default_aa_code = SystemContractCode { code: bytes_to_be_words(default_aa_bytecode), hash: default_aa_hash, }; - BaseSystemContracts { + Ok(BaseSystemContracts { bootloader: bootloader_code, default_aa: default_aa_code, - } + }) } /// Returns bytecodes for factory deps with the specified `hashes`. @@ -155,7 +157,10 @@ impl FactoryDepsDal<'_, '_> { } /// Removes all factory deps with a miniblock number strictly greater than the specified `block_number`. - pub async fn rollback_factory_deps(&mut self, block_number: MiniblockNumber) { + pub async fn rollback_factory_deps( + &mut self, + block_number: MiniblockNumber, + ) -> sqlx::Result<()> { sqlx::query!( r#" DELETE FROM factory_deps @@ -165,7 +170,7 @@ impl FactoryDepsDal<'_, '_> { block_number.0 as i64 ) .execute(self.storage.conn()) - .await - .unwrap(); + .await?; + Ok(()) } } diff --git a/core/lib/dal/src/protocol_versions_dal.rs b/core/lib/dal/src/protocol_versions_dal.rs index 7c2079ec4268..40da0d554da7 100644 --- a/core/lib/dal/src/protocol_versions_dal.rs +++ b/core/lib/dal/src/protocol_versions_dal.rs @@ -1,5 +1,6 @@ use std::convert::TryInto; +use anyhow::Context as _; use zksync_contracts::{BaseSystemContracts, BaseSystemContractsHashes}; use zksync_types::{ protocol_version::{L1VerifierConfig, ProtocolUpgradeTx, ProtocolVersion, VerifierParams}, @@ -142,7 +143,7 @@ impl ProtocolVersionsDal<'_, '_> { pub async fn base_system_contracts_by_timestamp( &mut self, current_timestamp: u64, - ) -> (BaseSystemContracts, ProtocolVersionId) { + ) -> anyhow::Result<(BaseSystemContracts, ProtocolVersionId)> { let row = sqlx::query!( r#" SELECT @@ -162,7 +163,11 @@ impl ProtocolVersionsDal<'_, '_> { ) .fetch_one(self.storage.conn()) .await - .unwrap(); + .context("cannot fetch system contract hashes")?; + + let protocol_version = (row.id as u16) + .try_into() + .context("bogus protocol version ID")?; let contracts = self .storage .factory_deps_dal() @@ -170,14 +175,14 @@ impl ProtocolVersionsDal<'_, '_> { H256::from_slice(&row.bootloader_code_hash), H256::from_slice(&row.default_account_code_hash), ) - .await; - (contracts, (row.id as u16).try_into().unwrap()) + .await?; + Ok((contracts, protocol_version)) } pub async fn load_base_system_contracts_by_version_id( &mut self, version_id: u16, - ) -> Option { + ) -> anyhow::Result> { let row = sqlx::query!( r#" SELECT @@ -192,20 +197,21 @@ impl ProtocolVersionsDal<'_, '_> { ) .fetch_optional(self.storage.conn()) .await - .unwrap(); - if let Some(row) = row { - Some( - self.storage - .factory_deps_dal() - .get_base_system_contracts( - H256::from_slice(&row.bootloader_code_hash), - H256::from_slice(&row.default_account_code_hash), - ) - .await, - ) + .context("cannot fetch system contract hashes")?; + + Ok(if let Some(row) = row { + let contracts = self + .storage + .factory_deps_dal() + .get_base_system_contracts( + H256::from_slice(&row.bootloader_code_hash), + H256::from_slice(&row.default_account_code_hash), + ) + .await?; + Some(contracts) } else { None - } + }) } pub async fn load_previous_version( diff --git a/core/lib/vm_utils/src/storage.rs b/core/lib/vm_utils/src/storage.rs index 1794b4546b1f..3c6d8d0221ba 100644 --- a/core/lib/vm_utils/src/storage.rs +++ b/core/lib/vm_utils/src/storage.rs @@ -283,7 +283,8 @@ impl L1BatchParamsProvider { let base_system_contracts = storage .factory_deps_dal() .get_base_system_contracts(contract_hashes.bootloader, contract_hashes.default_aa) - .await; + .await + .context("failed getting base system contracts")?; Ok(l1_batch_params( first_miniblock_in_batch.l1_batch_number, diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs index 626f747072d5..6543e37e3937 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs @@ -525,8 +525,11 @@ impl ZksNamespace { let method_latency = API_METRICS.start_call(METHOD_NAME); let mut storage = self.access_storage(METHOD_NAME).await?; - let bytecode = storage.factory_deps_dal().get_factory_dep(hash).await; - + let bytecode = storage + .factory_deps_dal() + .get_factory_dep(hash) + .await + .map_err(|err| internal_error(METHOD_NAME, err))?; method_latency.observe(); Ok(bytecode) } diff --git a/core/lib/zksync_core/src/block_reverter/mod.rs b/core/lib/zksync_core/src/block_reverter/mod.rs index 3b1ab41becce..bbd4e307045f 100644 --- a/core/lib/zksync_core/src/block_reverter/mod.rs +++ b/core/lib/zksync_core/src/block_reverter/mod.rs @@ -261,8 +261,8 @@ impl BlockReverter { transaction .factory_deps_dal() .rollback_factory_deps(last_miniblock_to_keep) - .await; - + .await + .expect("Failed rolling back factory dependencies"); tracing::info!("rolling back storage..."); #[allow(deprecated)] transaction @@ -270,7 +270,6 @@ impl BlockReverter { .rollback_storage(last_miniblock_to_keep) .await .expect("failed rolling back storage"); - tracing::info!("rolling back storage logs..."); transaction .storage_logs_dal() diff --git a/core/lib/zksync_core/src/state_keeper/io/fee_address_migration.rs b/core/lib/zksync_core/src/state_keeper/io/fee_address_migration.rs index 90d3eebffc3a..84fdc8e44cff 100644 --- a/core/lib/zksync_core/src/state_keeper/io/fee_address_migration.rs +++ b/core/lib/zksync_core/src/state_keeper/io/fee_address_migration.rs @@ -10,7 +10,9 @@ use zksync_dal::{ConnectionPool, StorageProcessor}; use zksync_types::MiniblockNumber; /// Runs the migration for pending miniblocks. -pub(crate) async fn migrate_pending_miniblocks(storage: &mut StorageProcessor<'_>) { +pub(crate) async fn migrate_pending_miniblocks( + storage: &mut StorageProcessor<'_>, +) -> anyhow::Result<()> { let started_at = Instant::now(); tracing::info!("Started migrating `fee_account_address` for pending miniblocks"); @@ -19,10 +21,10 @@ pub(crate) async fn migrate_pending_miniblocks(storage: &mut StorageProcessor<'_ .blocks_dal() .check_l1_batches_have_fee_account_address() .await - .expect("Failed getting metadata for l1_batches table"); + .context("failed getting metadata for l1_batches table")?; if !l1_batches_have_fee_account_address { tracing::info!("`l1_batches.fee_account_address` column is removed; assuming that the migration is complete"); - return; + return Ok(()); } #[allow(deprecated)] @@ -30,9 +32,10 @@ pub(crate) async fn migrate_pending_miniblocks(storage: &mut StorageProcessor<'_ .blocks_dal() .copy_fee_account_address_for_pending_miniblocks() .await - .expect("Failed migrating `fee_account_address` for pending miniblocks"); + .context("failed migrating `fee_account_address` for pending miniblocks")?; let elapsed = started_at.elapsed(); tracing::info!("Migrated `fee_account_address` for {rows_affected} miniblocks in {elapsed:?}"); + Ok(()) } /// Runs the migration for non-pending miniblocks. Should be run as a background task. diff --git a/core/lib/zksync_core/src/state_keeper/io/mempool.rs b/core/lib/zksync_core/src/state_keeper/io/mempool.rs index c1ae3474d303..ee635f3728b3 100644 --- a/core/lib/zksync_core/src/state_keeper/io/mempool.rs +++ b/core/lib/zksync_core/src/state_keeper/io/mempool.rs @@ -90,12 +90,8 @@ impl StateKeeperIO for MempoolIO { self.current_miniblock_number } - async fn load_pending_batch(&mut self) -> Option { - let mut storage = self - .pool - .access_storage_tagged("state_keeper") - .await - .unwrap(); + async fn load_pending_batch(&mut self) -> anyhow::Result> { + let mut storage = self.pool.access_storage_tagged("state_keeper").await?; let pending_miniblock_header = self .l1_batch_params_provider @@ -106,8 +102,11 @@ impl StateKeeperIO for MempoolIO { "failed loading first miniblock for L1 batch #{}", self.current_l1_batch_number ) - }) - .unwrap()?; + })?; + let Some(pending_miniblock_header) = pending_miniblock_header else { + return Ok(None); + }; + let (system_env, l1_batch_env) = self .l1_batch_params_provider .load_l1_batch_params( @@ -122,8 +121,7 @@ impl StateKeeperIO for MempoolIO { "failed loading params for L1 batch #{}", self.current_l1_batch_number ) - }) - .unwrap(); + })?; let pending_batch_data = load_pending_batch(&mut storage, system_env, l1_batch_env) .await .with_context(|| { @@ -131,8 +129,7 @@ impl StateKeeperIO for MempoolIO { "failed loading data for re-execution for pending L1 batch #{}", self.current_l1_batch_number ) - }) - .unwrap(); + })?; let PendingBatchData { l1_batch_env, @@ -149,17 +146,17 @@ impl StateKeeperIO for MempoolIO { gas_per_pubdata: gas_per_pubdata as u32, }; - Some(PendingBatchData { + Ok(Some(PendingBatchData { l1_batch_env, system_env, pending_miniblocks, - }) + })) } async fn wait_for_new_batch_params( &mut self, max_wait: Duration, - ) -> Option<(SystemEnv, L1BatchEnv)> { + ) -> anyhow::Result> { let deadline = Instant::now() + max_wait; // Block until at least one transaction in the mempool can match the filter (or timeout happens). @@ -172,22 +169,21 @@ impl StateKeeperIO for MempoolIO { deadline.into(), sleep_past(self.prev_miniblock_timestamp, self.current_miniblock_number), ); - let current_timestamp = current_timestamp.await.ok()?; + let Some(current_timestamp) = current_timestamp.await.ok() else { + return Ok(None); + }; tracing::trace!( "Fee input for L1 batch #{} is {:#?}", self.current_l1_batch_number.0, self.filter.fee_input ); - let mut storage = self - .pool - .access_storage_tagged("state_keeper") - .await - .unwrap(); + let mut storage = self.pool.access_storage_tagged("state_keeper").await?; let (base_system_contracts, protocol_version) = storage .protocol_versions_dal() .base_system_contracts_by_timestamp(current_timestamp) - .await; + .await + .context("Failed loading base system contracts")?; drop(storage); // We create a new filter each time, since parameters may change and a previously @@ -203,8 +199,8 @@ impl StateKeeperIO for MempoolIO { } // We only need to get the root hash when we're certain that we have a new transaction. - let prev_l1_batch_hash = self.wait_for_previous_l1_batch_hash().await; - return Some(l1_batch_params( + let prev_l1_batch_hash = self.wait_for_previous_l1_batch_hash().await?; + return Ok(Some(l1_batch_params( self.current_l1_batch_number, self.fee_account, current_timestamp, @@ -217,31 +213,32 @@ impl StateKeeperIO for MempoolIO { protocol_version, self.get_virtual_blocks_count(true, self.current_miniblock_number.0), self.chain_id, - )); + ))); } - None + Ok(None) } // Returns the pair of timestamp and the number of virtual blocks to be produced in this miniblock async fn wait_for_new_miniblock_params( &mut self, max_wait: Duration, - ) -> Option { + ) -> anyhow::Result> { // We must provide different timestamps for each miniblock. // If miniblock sealing interval is greater than 1 second then `sleep_past` won't actually sleep. - let timestamp = tokio::time::timeout( + let timeout_result = tokio::time::timeout( max_wait, sleep_past(self.prev_miniblock_timestamp, self.current_miniblock_number), ) - .await - .ok()?; + .await; + let Ok(timestamp) = timeout_result else { + return Ok(None); + }; let virtual_blocks = self.get_virtual_blocks_count(false, self.current_miniblock_number.0); - - Some(MiniblockParams { + Ok(Some(MiniblockParams { timestamp, virtual_blocks, - }) + })) } async fn wait_for_next_tx(&mut self, max_wait: Duration) -> Option { @@ -266,32 +263,27 @@ impl StateKeeperIO for MempoolIO { self.mempool.insert(vec![tx], HashMap::new()); } - async fn reject(&mut self, rejected: &Transaction, error: &str) { - assert!( + async fn reject(&mut self, rejected: &Transaction, error: &str) -> anyhow::Result<()> { + anyhow::ensure!( !rejected.is_l1(), - "L1 transactions should not be rejected: {}", - error + "L1 transactions should not be rejected: {error}" ); // Reset the nonces in the mempool, but don't insert the transaction back. self.mempool.rollback(rejected); // Mark tx as rejected in the storage. - let mut storage = self - .pool - .access_storage_tagged("state_keeper") - .await - .unwrap(); + let mut storage = self.pool.access_storage_tagged("state_keeper").await?; KEEPER_METRICS.rejected_transactions.inc(); tracing::warn!( - "transaction {} is rejected with error {}", - rejected.hash(), - error + "transaction {} is rejected with error: {error}", + rejected.hash() ); storage .transactions_dal() - .mark_tx_as_rejected(rejected.hash(), &format!("rejected: {}", error)) + .mark_tx_as_rejected(rejected.hash(), &format!("rejected: {error}")) .await; + Ok(()) } async fn seal_miniblock(&mut self, updates_manager: &UpdatesManager) { @@ -340,7 +332,7 @@ impl StateKeeperIO for MempoolIO { } let pool = self.pool.clone(); - let mut storage = pool.access_storage_tagged("state_keeper").await.unwrap(); + let mut storage = pool.access_storage_tagged("state_keeper").await?; let fictive_miniblock = updates_manager .seal_l1_batch( @@ -356,35 +348,27 @@ impl StateKeeperIO for MempoolIO { Ok(()) } - async fn load_previous_batch_version_id(&mut self) -> Option { - let mut storage = self - .pool - .access_storage_tagged("state_keeper") - .await - .unwrap(); + async fn load_previous_batch_version_id(&mut self) -> anyhow::Result { + let mut storage = self.pool.access_storage_tagged("state_keeper").await?; let prev_l1_batch_number = self.current_l1_batch_number - 1; self.l1_batch_params_provider .load_l1_batch_protocol_version(&mut storage, prev_l1_batch_number) .await .with_context(|| { format!("failed loading protocol version for L1 batch #{prev_l1_batch_number}") - }) - .unwrap() + })? + .with_context(|| format!("L1 batch #{prev_l1_batch_number} misses protocol version")) } async fn load_upgrade_tx( &mut self, version_id: ProtocolVersionId, - ) -> Option { - let mut storage = self - .pool - .access_storage_tagged("state_keeper") - .await - .unwrap(); - storage + ) -> anyhow::Result> { + let mut storage = self.pool.access_storage_tagged("state_keeper").await?; + Ok(storage .protocol_versions_dal() .get_protocol_upgrade_tx(version_id) - .await + .await) } } @@ -465,7 +449,7 @@ impl MempoolIO { let l1_batch_params_provider = L1BatchParamsProvider::new(&mut storage) .await .context("failed initializing L1 batch params provider")?; - fee_address_migration::migrate_pending_miniblocks(&mut storage).await; + fee_address_migration::migrate_pending_miniblocks(&mut storage).await?; drop(storage); Ok(Self { @@ -502,18 +486,14 @@ impl MempoolIO { self.prev_miniblock_timestamp = miniblock.timestamp; } - async fn wait_for_previous_l1_batch_hash(&self) -> H256 { + async fn wait_for_previous_l1_batch_hash(&self) -> anyhow::Result { tracing::trace!( "Getting previous L1 batch hash for L1 batch #{}", self.current_l1_batch_number ); let wait_latency = KEEPER_METRICS.wait_for_prev_hash_time.start(); - let mut storage = self - .pool - .access_storage_tagged("state_keeper") - .await - .unwrap(); + let mut storage = self.pool.access_storage_tagged("state_keeper").await?; let prev_l1_batch_number = self.current_l1_batch_number - 1; let (batch_hash, _) = self .l1_batch_params_provider @@ -521,15 +501,14 @@ impl MempoolIO { .await .with_context(|| { format!("error waiting for params for L1 batch #{prev_l1_batch_number}") - }) - .unwrap(); + })?; wait_latency.observe(); tracing::trace!( "Got previous L1 batch hash: {batch_hash:?} for L1 batch #{}", self.current_l1_batch_number ); - batch_hash + Ok(batch_hash) } /// "virtual_blocks_per_miniblock" will be created either if the miniblock_number % virtual_blocks_interval == 0 or diff --git a/core/lib/zksync_core/src/state_keeper/io/mod.rs b/core/lib/zksync_core/src/state_keeper/io/mod.rs index 66f9d6cec49a..482590a67ee0 100644 --- a/core/lib/zksync_core/src/state_keeper/io/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/io/mod.rs @@ -62,35 +62,41 @@ pub struct MiniblockParams { /// `StateKeeperIO` provides the interactive layer for the state keeper: /// it's used to receive volatile parameters (such as batch parameters), and also it's used to perform /// mutable operations on the persistent state (e.g. persist executed batches). +/// +/// All errors returned from this method are treated as unrecoverable. #[async_trait] pub trait StateKeeperIO: 'static + Send + IoSealCriteria { /// Returns the number of the currently processed L1 batch. fn current_l1_batch_number(&self) -> L1BatchNumber; /// Returns the number of the currently processed miniblock (aka L2 block). fn current_miniblock_number(&self) -> MiniblockNumber; + /// Returns the data on the batch that was not sealed before the server restart. /// See `PendingBatchData` doc-comment for details. - async fn load_pending_batch(&mut self) -> Option; + async fn load_pending_batch(&mut self) -> anyhow::Result>; + /// Blocks for up to `max_wait` until the parameters for the next L1 batch are available. /// Returns the data required to initialize the VM for the next batch. async fn wait_for_new_batch_params( &mut self, max_wait: Duration, - ) -> Option<(SystemEnv, L1BatchEnv)>; + ) -> anyhow::Result>; + /// Blocks for up to `max_wait` until the parameters for the next miniblock are available. async fn wait_for_new_miniblock_params( &mut self, max_wait: Duration, - ) -> Option; + ) -> anyhow::Result>; + /// Blocks for up to `max_wait` until the next transaction is available for execution. /// Returns `None` if no transaction became available until the timeout. async fn wait_for_next_tx(&mut self, max_wait: Duration) -> Option; /// Marks the transaction as "not executed", so it can be retrieved from the IO again. async fn rollback(&mut self, tx: Transaction); /// Marks the transaction as "rejected", e.g. one that is not correct and can't be executed. - async fn reject(&mut self, tx: &Transaction, error: &str); - /// Marks the miniblock (aka L2 block) as sealed. - /// Returns the timestamp for the next miniblock. + async fn reject(&mut self, tx: &Transaction, error: &str) -> anyhow::Result<()>; + + /// Marks the miniblock (aka L2 block) as sealed. Returns the timestamp for the next miniblock. async fn seal_miniblock(&mut self, updates_manager: &UpdatesManager); /// Marks the L1 batch as sealed. async fn seal_l1_batch( @@ -100,11 +106,14 @@ pub trait StateKeeperIO: 'static + Send + IoSealCriteria { l1_batch_env: &L1BatchEnv, finished_batch: FinishedL1Batch, ) -> anyhow::Result<()>; + /// Loads protocol version of the previous l1 batch. - async fn load_previous_batch_version_id(&mut self) -> Option; + async fn load_previous_batch_version_id(&mut self) -> anyhow::Result; /// Loads protocol upgrade tx for given version. - async fn load_upgrade_tx(&mut self, version_id: ProtocolVersionId) - -> Option; + async fn load_upgrade_tx( + &mut self, + version_id: ProtocolVersionId, + ) -> anyhow::Result>; } impl fmt::Debug for dyn StateKeeperIO { diff --git a/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs b/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs index 437bd46a4d23..725a635e186a 100644 --- a/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs +++ b/core/lib/zksync_core/src/state_keeper/io/tests/mod.rs @@ -79,7 +79,7 @@ async fn test_filter_with_pending_batch() { // Before the mempool knows there is a pending batch, the filter is still set to the default values. assert_eq!(mempool.filter(), &L2TxFilter::default()); - mempool.load_pending_batch().await; + mempool.load_pending_batch().await.unwrap(); let (want_base_fee, want_gas_per_pubdata) = derive_base_fee_and_gas_per_pubdata(fee_input, ProtocolVersionId::latest().into()); let want_filter = L2TxFilter { @@ -161,11 +161,12 @@ async fn test_timestamps_are_distinct( .await; tester.insert_tx(&mut guard, tx_filter.fee_per_gas, tx_filter.gas_per_pubdata); - let batch_params = mempool + let (_, l1_batch_env) = mempool .wait_for_new_batch_params(Duration::from_secs(10)) .await + .unwrap() .expect("No batch params in the test mempool"); - assert!(batch_params.1.timestamp > prev_miniblock_timestamp); + assert!(l1_batch_env.timestamp > prev_miniblock_timestamp); } #[tokio::test] @@ -451,7 +452,7 @@ async fn miniblock_processing_after_snapshot_recovery() { mempool.current_l1_batch_number(), snapshot_recovery.l1_batch_number + 1 ); - assert!(mempool.load_pending_batch().await.is_none()); + assert!(mempool.load_pending_batch().await.unwrap().is_none()); // Insert a transaction into the mempool in order to open a new batch. let tx_filter = l2_tx_filter( @@ -472,7 +473,8 @@ async fn miniblock_processing_after_snapshot_recovery() { let (system_env, l1_batch_env) = mempool .wait_for_new_batch_params(Duration::from_secs(10)) .await - .unwrap(); + .unwrap() + .expect("no batch params generated"); assert_eq!(l1_batch_env.number, snapshot_recovery.l1_batch_number + 1); assert_eq!( l1_batch_env.previous_batch_hash, @@ -541,7 +543,11 @@ async fn miniblock_processing_after_snapshot_recovery() { snapshot_recovery.l1_batch_number + 1 ); - let pending_batch = mempool.load_pending_batch().await.unwrap(); + let pending_batch = mempool + .load_pending_batch() + .await + .unwrap() + .expect("no pending batch"); assert_eq!( pending_batch.l1_batch_env.number, snapshot_recovery.l1_batch_number + 1 @@ -665,6 +671,7 @@ async fn different_timestamp_for_miniblocks_in_same_batch() { let miniblock_params = mempool .wait_for_new_miniblock_params(Duration::from_secs(10)) .await - .unwrap(); + .unwrap() + .expect("no new miniblock params"); assert!(miniblock_params.timestamp > current_timestamp); } diff --git a/core/lib/zksync_core/src/state_keeper/keeper.rs b/core/lib/zksync_core/src/state_keeper/keeper.rs index e331aec9763a..581344ad0223 100644 --- a/core/lib/zksync_core/src/state_keeper/keeper.rs +++ b/core/lib/zksync_core/src/state_keeper/keeper.rs @@ -116,12 +116,18 @@ impl ZkSyncStateKeeper { self.io.current_miniblock_number() ); + let pending_batch_params = self + .io + .load_pending_batch() + .await + .context("failed loading pending L1 batch")?; + // Re-execute pending batch if it exists. Otherwise, initialize a new batch. let PendingBatchData { mut l1_batch_env, mut system_env, pending_miniblocks, - } = match self.io.load_pending_batch().await { + } = match pending_batch_params { Some(params) => { tracing::info!( "There exists a pending batch consisting of {} miniblocks, the first one is {}", @@ -129,8 +135,8 @@ impl ZkSyncStateKeeper { params .pending_miniblocks .first() - .map(|miniblock| miniblock.number) - .context("Empty pending block represented as Some")?, + .context("expected at least one pending miniblock")? + .number ); params } @@ -197,7 +203,7 @@ impl ZkSyncStateKeeper { finished_batch, ) .await - .context("seal_l1_batch")?; + .with_context(|| format!("failed sealing L1 batch {l1_batch_env:?}"))?; if let Some(delta) = l1_batch_seal_delta { L1_BATCH_METRICS.seal_delta.observe(delta.elapsed()); } @@ -218,7 +224,7 @@ impl ZkSyncStateKeeper { let version_changed = system_env.version != sealed_batch_protocol_version; protocol_upgrade_tx = if version_changed { - self.io.load_upgrade_tx(system_env.version).await + self.load_upgrade_tx(system_env.version).await? } else { None }; @@ -242,48 +248,35 @@ impl ZkSyncStateKeeper { // transaction to the genesis protocol version version. let first_batch_in_shared_bridge = l1_batch_number == L1BatchNumber(1) && !protocol_version.is_pre_shared_bridge(); - let previous_batch_protocol_version = - self.io.load_previous_batch_version_id().await.unwrap(); + let previous_batch_protocol_version = self.io.load_previous_batch_version_id().await?; let version_changed = protocol_version != previous_batch_protocol_version; - let protocol_upgrade_tx = self.io.load_upgrade_tx(protocol_version).await; + let mut protocol_upgrade_tx = if version_changed || first_batch_in_shared_bridge { + self.io.load_upgrade_tx(protocol_version).await? + } else { + None + }; - let protocol_upgrade_tx = if pending_miniblocks.is_empty() - && (version_changed || first_batch_in_shared_bridge) - { - // We have a new upgrade transaction - either a regular protocol upgrade or a `setChainId` upgrade. - // If we are running an EN, `protocol_upgrade_tx` will be `None` here since it is fetched from the main node. - tracing::info!( - "There is an new upgrade tx to be executed in batch #{}", - l1_batch_number - ); - protocol_upgrade_tx - } else if !pending_miniblocks.is_empty() - && (version_changed || first_batch_in_shared_bridge) - { + // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block + // then it must be the first one in `txs_to_reexecute`. + if !pending_miniblocks.is_empty() && protocol_upgrade_tx.is_some() { // We already processed the upgrade tx but did not seal the batch it was in. - // Sanity check: if `txs_to_reexecute` is not empty and upgrade tx is present for this block - // then it must be the first one in `txs_to_reexecute`. - if protocol_upgrade_tx.is_some() { - let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; - assert_eq!( - first_tx_to_reexecute.tx_format(), - TransactionType::ProtocolUpgradeTransaction, - "Expected an upgrade transaction to be the first one in pending_miniblocks, but found {:?}", - first_tx_to_reexecute.hash() - ); - } + let first_tx_to_reexecute = &pending_miniblocks[0].txs[0]; + assert_eq!( + first_tx_to_reexecute.tx_format(), + TransactionType::ProtocolUpgradeTransaction, + "Expected an upgrade transaction to be the first one in pending_miniblocks, but found {:?}", + first_tx_to_reexecute.hash() + ); tracing::info!( - "There is a protocol upgrade in batch #{}, upgrade tx already processed", - l1_batch_number + "There is a protocol upgrade in batch #{l1_batch_number}, upgrade tx already processed" ); - None - } else { - // We do not have any upgrade transactions in this batch. - tracing::info!("There is no protocol upgrade in batch #{}", l1_batch_number); - None - }; + protocol_upgrade_tx = None; // The protocol upgrade was already executed + } + if protocol_upgrade_tx.is_some() { + tracing::info!("There is a new upgrade tx to be executed in batch #{l1_batch_number}"); + } Ok(protocol_upgrade_tx) } @@ -291,9 +284,24 @@ impl ZkSyncStateKeeper { *self.stop_receiver.borrow() } + async fn load_upgrade_tx( + &mut self, + protocol_version: ProtocolVersionId, + ) -> anyhow::Result> { + self.io + .load_upgrade_tx(protocol_version) + .await + .with_context(|| format!("failed loading upgrade transaction for {protocol_version:?}")) + } + async fn wait_for_new_batch_params(&mut self) -> Result<(SystemEnv, L1BatchEnv), Error> { while !self.is_canceled() { - if let Some(params) = self.io.wait_for_new_batch_params(POLL_WAIT_DURATION).await { + if let Some(params) = self + .io + .wait_for_new_batch_params(POLL_WAIT_DURATION) + .await + .context("error waiting for new L1 batch params")? + { return Ok(params); } } @@ -306,6 +314,7 @@ impl ZkSyncStateKeeper { .io .wait_for_new_miniblock_params(POLL_WAIT_DURATION) .await + .context("error waiting for new miniblock params")? { return Ok(params); } @@ -518,7 +527,10 @@ impl ZkSyncStateKeeper { } SealResolution::Unexecutable(reason) => { batch_executor.rollback_last_tx().await; - self.io.reject(&tx, reason).await; + self.io + .reject(&tx, reason) + .await + .with_context(|| format!("cannot reject transaction {tx_hash:?}"))?; } }; diff --git a/core/lib/zksync_core/src/state_keeper/tests/tester.rs b/core/lib/zksync_core/src/state_keeper/tests/tester.rs index 0f077eacf71b..0c3e82ec5282 100644 --- a/core/lib/zksync_core/src/state_keeper/tests/tester.rs +++ b/core/lib/zksync_core/src/state_keeper/tests/tester.rs @@ -643,21 +643,21 @@ impl StateKeeperIO for TestIO { self.miniblock_number } - async fn load_pending_batch(&mut self) -> Option { - self.scenario.pending_batch.take() + async fn load_pending_batch(&mut self) -> anyhow::Result> { + Ok(self.scenario.pending_batch.take()) } async fn wait_for_new_batch_params( &mut self, _max_wait: Duration, - ) -> Option<(SystemEnv, L1BatchEnv)> { + ) -> anyhow::Result> { let first_miniblock_info = L2BlockEnv { number: self.miniblock_number.0, timestamp: self.timestamp, prev_block_hash: H256::zero(), max_virtual_blocks_to_create: 1, }; - Some(( + Ok(Some(( SystemEnv { zk_porter_available: false, version: self.protocol_version, @@ -676,18 +676,18 @@ impl StateKeeperIO for TestIO { enforced_base_fee: None, first_l2_block: first_miniblock_info, }, - )) + ))) } async fn wait_for_new_miniblock_params( &mut self, _max_wait: Duration, - ) -> Option { - Some(MiniblockParams { + ) -> anyhow::Result> { + Ok(Some(MiniblockParams { timestamp: self.timestamp, // 1 is just a constant used for tests. virtual_blocks: 1, - }) + })) } async fn wait_for_next_tx(&mut self, max_wait: Duration) -> Option { @@ -721,7 +721,7 @@ impl StateKeeperIO for TestIO { self.skipping_txs = false; } - async fn reject(&mut self, tx: &Transaction, error: &str) { + async fn reject(&mut self, tx: &Transaction, error: &str) -> anyhow::Result<()> { let action = self.pop_next_item("reject"); let ScenarioItem::Reject(_, expected_tx, expected_err) = action else { panic!("Unexpected action: {:?}", action); @@ -736,6 +736,7 @@ impl StateKeeperIO for TestIO { ); } self.skipping_txs = false; + Ok(()) } async fn seal_miniblock(&mut self, updates_manager: &UpdatesManager) { @@ -778,15 +779,15 @@ impl StateKeeperIO for TestIO { Ok(()) } - async fn load_previous_batch_version_id(&mut self) -> Option { - Some(self.previous_batch_protocol_version) + async fn load_previous_batch_version_id(&mut self) -> anyhow::Result { + Ok(self.previous_batch_protocol_version) } async fn load_upgrade_tx( &mut self, version_id: ProtocolVersionId, - ) -> Option { - self.protocol_upgrade_txs.get(&version_id).cloned() + ) -> anyhow::Result> { + Ok(self.protocol_upgrade_txs.get(&version_id).cloned()) } } diff --git a/core/lib/zksync_core/src/sync_layer/external_io.rs b/core/lib/zksync_core/src/sync_layer/external_io.rs index d0c4e2e4b2a9..b67062bc27f0 100644 --- a/core/lib/zksync_core/src/sync_layer/external_io.rs +++ b/core/lib/zksync_core/src/sync_layer/external_io.rs @@ -82,7 +82,7 @@ impl ExternalIO { .context("failed initializing L1 batch params provider")?; // We must run the migration for pending miniblocks synchronously, since we use `fee_account_address` // from a pending miniblock in `load_pending_batch()` implementation. - fee_address_migration::migrate_pending_miniblocks(&mut storage).await; + fee_address_migration::migrate_pending_miniblocks(&mut storage).await?; drop(storage); tracing::info!( @@ -122,12 +122,12 @@ impl ExternalIO { self.prev_miniblock_hash = miniblock.get_miniblock_hash(); } - async fn wait_for_previous_l1_batch_hash(&self) -> H256 { + async fn wait_for_previous_l1_batch_hash(&self) -> anyhow::Result { tracing::info!( "Getting previous L1 batch hash for L1 batch #{}", self.current_l1_batch_number ); - let mut storage = self.pool.access_storage_tagged("sync_layer").await.unwrap(); + let mut storage = self.pool.access_storage_tagged("sync_layer").await?; let wait_latency = KEEPER_METRICS.wait_for_prev_hash_time.start(); let prev_l1_batch_number = self.current_l1_batch_number - 1; let (hash, _) = self @@ -136,26 +136,25 @@ impl ExternalIO { .await .with_context(|| { format!("error waiting for params for L1 batch #{prev_l1_batch_number}") - }) - .unwrap(); + })?; wait_latency.observe(); - hash + Ok(hash) } async fn load_base_system_contracts_by_version_id( &self, id: ProtocolVersionId, - ) -> BaseSystemContracts { + ) -> anyhow::Result { let base_system_contracts = self .pool .access_storage_tagged("sync_layer") - .await - .unwrap() + .await? .protocol_versions_dal() .load_base_system_contracts_by_version_id(id as u16) - .await; + .await + .context("failed loading base system contracts")?; - match base_system_contracts { + Ok(match base_system_contracts { Some(version) => version, None => { tracing::info!("Fetching protocol version {id:?} from the main node"); @@ -164,15 +163,17 @@ impl ExternalIO { .main_node_client .fetch_protocol_version(id) .await - .expect("Failed to fetch protocol version from the main node") - .expect("Protocol version is missing on the main node"); + .context("failed to fetch protocol version from the main node")? + .context("protocol version is missing on the main node")?; self.pool .access_storage_tagged("sync_layer") - .await - .unwrap() + .await? .protocol_versions_dal() .save_protocol_version( - protocol_version.version_id.try_into().unwrap(), + protocol_version + .version_id + .try_into() + .context("cannot convert protocol version")?, protocol_version.timestamp, protocol_version.verification_keys_hashes, protocol_version.base_system_contracts, @@ -184,29 +185,35 @@ impl ExternalIO { let bootloader = self .get_base_system_contract(protocol_version.base_system_contracts.bootloader) - .await; + .await + .with_context(|| { + format!("cannot fetch bootloader code for {protocol_version:?}") + })?; let default_aa = self .get_base_system_contract(protocol_version.base_system_contracts.default_aa) - .await; + .await + .with_context(|| { + format!("cannot fetch default AA code for {protocol_version:?}") + })?; BaseSystemContracts { bootloader, default_aa, } } - } + }) } - async fn get_base_system_contract(&self, hash: H256) -> SystemContractCode { + async fn get_base_system_contract(&self, hash: H256) -> anyhow::Result { let bytecode = self .pool .access_storage_tagged("sync_layer") - .await - .unwrap() + .await? .factory_deps_dal() .get_factory_dep(hash) - .await; + .await + .with_context(|| format!("failed getting bytecode for hash {hash:?}"))?; - match bytecode { + Ok(match bytecode { Some(bytecode) => SystemContractCode { code: bytes_to_be_words(bytecode), hash, @@ -220,25 +227,24 @@ impl ExternalIO { .main_node_client .fetch_system_contract_by_hash(hash) .await - .expect("Failed to fetch base system contract bytecode from the main node") - .expect("Base system contract is missing on the main node"); + .context("failed to fetch base system contract bytecode from the main node")? + .context("base system contract is missing on the main node")?; self.pool .access_storage_tagged("sync_layer") - .await - .unwrap() + .await? .factory_deps_dal() .insert_factory_deps( self.current_miniblock_number, &HashMap::from([(hash, contract_bytecode.clone())]), ) .await - .unwrap(); + .context("failed persisting system contract")?; SystemContractCode { code: bytes_to_be_words(contract_bytecode), hash, } } - } + }) } } @@ -265,10 +271,10 @@ impl StateKeeperIO for ExternalIO { self.current_miniblock_number } - async fn load_pending_batch(&mut self) -> Option { - let mut storage = self.pool.access_storage_tagged("sync_layer").await.unwrap(); + async fn load_pending_batch(&mut self) -> anyhow::Result> { + let mut storage = self.pool.access_storage_tagged("sync_layer").await?; - let mut pending_miniblock_header = self + let pending_miniblock_header = self .l1_batch_params_provider .load_first_miniblock_in_batch(&mut storage, self.current_l1_batch_number) .await @@ -277,25 +283,35 @@ impl StateKeeperIO for ExternalIO { "failed loading first miniblock for L1 batch #{}", self.current_l1_batch_number ) - }) - .unwrap()?; + })?; + let Some(mut pending_miniblock_header) = pending_miniblock_header else { + return Ok(None); + }; + if !pending_miniblock_header.has_protocol_version() { + let pending_miniblock_number = pending_miniblock_header.number(); // Fetch protocol version ID for pending miniblocks to know which VM to use to re-execute them. let sync_block = self .main_node_client - .fetch_l2_block(pending_miniblock_header.number(), false) + .fetch_l2_block(pending_miniblock_number, false) .await - .expect("Failed to fetch block from the main node") - .expect("Block must exist"); + .context("failed to fetch block from the main node")? + .with_context(|| { + format!("pending miniblock #{pending_miniblock_number} is missing on main node") + })?; // Loading base system contracts will insert protocol version in the database if it's not present there. - self.load_base_system_contracts_by_version_id(sync_block.protocol_version) - .await; + let protocol_version = sync_block.protocol_version; + self.load_base_system_contracts_by_version_id(protocol_version) + .await + .with_context(|| { + format!("cannot load base system contracts for {protocol_version:?}") + })?; storage .blocks_dal() - .set_protocol_version_for_pending_miniblocks(sync_block.protocol_version) + .set_protocol_version_for_pending_miniblocks(protocol_version) .await - .unwrap(); - pending_miniblock_header.set_protocol_version(sync_block.protocol_version); + .context("failed setting protocol version for pending miniblocks")?; + pending_miniblock_header.set_protocol_version(protocol_version); } let (system_env, l1_batch_env) = self @@ -312,8 +328,7 @@ impl StateKeeperIO for ExternalIO { "failed loading parameters for pending L1 batch #{}", self.current_l1_batch_number ) - }) - .unwrap(); + })?; let data = load_pending_batch(&mut storage, system_env, l1_batch_env) .await .with_context(|| { @@ -321,15 +336,14 @@ impl StateKeeperIO for ExternalIO { "failed loading data for re-execution for pending L1 batch #{}", self.current_l1_batch_number ) - }) - .unwrap(); - Some(data) + })?; + Ok(Some(data)) } async fn wait_for_new_batch_params( &mut self, max_wait: Duration, - ) -> Option<(SystemEnv, L1BatchEnv)> { + ) -> anyhow::Result> { tracing::debug!("Waiting for the new batch params"); for _ in 0..poll_iters(POLL_INTERVAL, max_wait) { match self.actions.pop_action() { @@ -343,11 +357,12 @@ impl StateKeeperIO for ExternalIO { protocol_version, first_miniblock_info: (miniblock_number, virtual_blocks), }) => { - assert_eq!( - number, self.current_l1_batch_number, - "Batch number mismatch" + anyhow::ensure!( + number == self.current_l1_batch_number, + "Batch number mismatch: expected {}, got {number}", + self.current_l1_batch_number ); - let previous_l1_batch_hash = self.wait_for_previous_l1_batch_hash().await; + let previous_l1_batch_hash = self.wait_for_previous_l1_batch_hash().await?; tracing::info!( "Previous L1 batch hash: {previous_l1_batch_hash:?}, previous miniblock hash: {:?}", self.prev_miniblock_hash @@ -355,8 +370,11 @@ impl StateKeeperIO for ExternalIO { let base_system_contracts = self .load_base_system_contracts_by_version_id(protocol_version) - .await; - return Some(l1_batch_params( + .await + .with_context(|| { + format!("cannot load base system contracts for {protocol_version:?}") + })?; + return Ok(Some(l1_batch_params( number, operator_address, timestamp, @@ -374,23 +392,23 @@ impl StateKeeperIO for ExternalIO { protocol_version, virtual_blocks, self.chain_id, - )); + ))); } Some(other) => { - panic!("Unexpected action in the action queue: {other:?}"); + anyhow::bail!("unexpected action in the action queue: {other:?}"); } None => { tokio::time::sleep(POLL_INTERVAL).await; } } } - None + Ok(None) } async fn wait_for_new_miniblock_params( &mut self, max_wait: Duration, - ) -> Option { + ) -> anyhow::Result> { // Wait for the next miniblock to appear in the queue. let actions = &mut self.actions; for _ in 0..poll_iters(POLL_INTERVAL, max_wait) { @@ -401,27 +419,28 @@ impl StateKeeperIO for ExternalIO { virtual_blocks, }) => { self.actions.pop_action(); // We found the miniblock, remove it from the queue. - assert_eq!( - number, self.current_miniblock_number, - "Miniblock number mismatch" + anyhow::ensure!( + number == self.current_miniblock_number, + "Miniblock number mismatch: expected {}, got {number}", + self.current_miniblock_number ); - return Some(MiniblockParams { + return Ok(Some(MiniblockParams { timestamp, virtual_blocks, - }); + })); } Some(SyncAction::SealBatch { virtual_blocks, .. }) => { // We've reached the next batch, so this situation would be handled by the batch sealer. // No need to pop the action from the queue. // It also doesn't matter which timestamp we return, since there will be no more miniblocks in this // batch. We return 0 to make it easy to detect if it ever appears somewhere. - return Some(MiniblockParams { + return Ok(Some(MiniblockParams { timestamp: 0, virtual_blocks, - }); + })); } Some(other) => { - panic!( + anyhow::bail!( "Unexpected action in the queue while waiting for the next miniblock: {other:?}" ); } @@ -430,7 +449,7 @@ impl StateKeeperIO for ExternalIO { } } } - None + Ok(None) } async fn wait_for_next_tx(&mut self, max_wait: Duration) -> Option { @@ -464,11 +483,11 @@ impl StateKeeperIO for ExternalIO { panic!("Rollback requested. Transaction hash: {:?}", tx.hash()); } - async fn reject(&mut self, tx: &Transaction, error: &str) { + async fn reject(&mut self, tx: &Transaction, error: &str) -> anyhow::Result<()> { // We are replaying the already executed transactions so no rejections are expected to occur. - panic!( - "Reject requested because of the following error: {}.\n Transaction hash is: {:?}", - error, + anyhow::bail!( + "Requested rejection of transaction {:?} because of the following error: {error}. \ + This is not supported on external node", tx.hash() ); } @@ -512,7 +531,7 @@ impl StateKeeperIO for ExternalIO { // We cannot start sealing an L1 batch until we've sealed all miniblocks included in it. self.miniblock_sealer_handle.wait_for_all_commands().await; - let mut storage = self.pool.access_storage_tagged("sync_layer").await.unwrap(); + let mut storage = self.pool.access_storage_tagged("sync_layer").await?; let fictive_miniblock = updates_manager .seal_l1_batch( &mut storage, @@ -530,23 +549,23 @@ impl StateKeeperIO for ExternalIO { Ok(()) } - async fn load_previous_batch_version_id(&mut self) -> Option { - let mut storage = self.pool.access_storage_tagged("sync_layer").await.unwrap(); + async fn load_previous_batch_version_id(&mut self) -> anyhow::Result { + let mut storage = self.pool.access_storage_tagged("sync_layer").await?; let prev_l1_batch_number = self.current_l1_batch_number - 1; self.l1_batch_params_provider .load_l1_batch_protocol_version(&mut storage, prev_l1_batch_number) .await .with_context(|| { format!("failed loading protocol version for L1 batch #{prev_l1_batch_number}") - }) - .unwrap() + })? + .with_context(|| format!("L1 batch #{prev_l1_batch_number} misses protocol version")) } async fn load_upgrade_tx( &mut self, _version_id: ProtocolVersionId, - ) -> Option { - // External node will fetch upgrade tx from the main node. - None + ) -> anyhow::Result> { + // External node will fetch upgrade tx from the main node + Ok(None) } } diff --git a/prover/witness_generator/src/basic_circuits.rs b/prover/witness_generator/src/basic_circuits.rs index 85f16c284491..b11ee733c83b 100644 --- a/prover/witness_generator/src/basic_circuits.rs +++ b/prover/witness_generator/src/basic_circuits.rs @@ -512,13 +512,15 @@ async fn generate_witness( .factory_deps_dal() .get_factory_dep(header.base_system_contracts_hashes.bootloader) .await + .expect("Failed fetching bootloader bytecode from DB") .expect("Bootloader bytecode should exist"); let bootloader_code = bytes_to_chunks(&bootloader_code_bytes); let account_bytecode_bytes = connection .factory_deps_dal() .get_factory_dep(header.base_system_contracts_hashes.default_aa) .await - .expect("Default aa bytecode should exist"); + .expect("Failed fetching default account bytecode from DB") + .expect("Default account bytecode should exist"); let account_bytecode = bytes_to_chunks(&account_bytecode_bytes); let bootloader_contents = expand_bootloader_contents(&input.initial_heap_content, protocol_version); From 376c09eddb8fd26cb823c5b2d1e9ce4a619610bb Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:28:30 +0100 Subject: [PATCH 030/106] feat(prover): Use new shivini function for 4844 circuits (#1205) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Start using the new shivini function for 4844 circuit ## Why ❔ * Needed for GPU provers --- prover/Cargo.lock | 2 +- prover/prover_fri/src/socket_listener.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/prover/Cargo.lock b/prover/Cargo.lock index 6b6d001c7547..11b4a660b95b 100644 --- a/prover/Cargo.lock +++ b/prover/Cargo.lock @@ -4914,7 +4914,7 @@ dependencies = [ [[package]] name = "shivini" version = "0.1.0" -source = "git+https://github.com/matter-labs/era-shivini.git?branch=v1.4.1#f4bf41f45a1c5bb3a9e487114bc314d68d4e1aaf" +source = "git+https://github.com/matter-labs/era-shivini.git?branch=v1.4.1#81d5baac09cb790b3e4c8ce681ed4fd0ab2e0234" dependencies = [ "bincode", "blake2 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/prover/prover_fri/src/socket_listener.rs b/prover/prover_fri/src/socket_listener.rs index 911762392b1c..a4144b5cacba 100644 --- a/prover/prover_fri/src/socket_listener.rs +++ b/prover/prover_fri/src/socket_listener.rs @@ -4,7 +4,8 @@ pub mod gpu_socket_listener { use anyhow::Context as _; use shivini::synthesis_utils::{ - init_base_layer_cs_for_repeated_proving, init_recursive_layer_cs_for_repeated_proving, + init_base_layer_cs_for_repeated_proving, init_eip4844_cs_for_repeated_proving, + init_recursive_layer_cs_for_repeated_proving, }; use tokio::{ io::copy, @@ -196,13 +197,12 @@ pub mod gpu_socket_listener { .context("get_finalization_hints()")?; init_recursive_layer_cs_for_repeated_proving(recursive_circuit, &finalization_hint) } - CircuitWrapper::Eip4844(_) => { + CircuitWrapper::Eip4844(circuit) => { let key = ProverServiceDataKey::eip4844(); let finalization_hint = keystore .load_finalization_hints(key) .context("get_finalization_hints()")?; - // Check shivini support. - todo!(); + init_eip4844_cs_for_repeated_proving(circuit, &finalization_hint) } }; tracing::info!( From cef6923fa4b6506f8c05df4c3447661432742e9b Mon Sep 17 00:00:00 2001 From: EmilLuta Date: Thu, 22 Feb 2024 14:37:53 +0100 Subject: [PATCH 031/106] fix(witness_generator): Add trusted setup to wit gens (#1207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- docker/witness-generator/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/witness-generator/Dockerfile b/docker/witness-generator/Dockerfile index 42dee7ba5d0b..57dfecc7efbf 100644 --- a/docker/witness-generator/Dockerfile +++ b/docker/witness-generator/Dockerfile @@ -11,6 +11,8 @@ FROM debian:bookworm-slim RUN apt-get update && apt-get install -y curl libpq5 ca-certificates && rm -rf /var/lib/apt/lists/* +COPY --from=builder /usr/src/zksync/trusted_setup.json /usr/bin/trusted_setup.json + COPY prover/vk_setup_data_generator_server_fri/data/ /prover/vk_setup_data_generator_server_fri/data/ COPY --from=builder /usr/src/zksync/target/release/zksync_witness_generator /usr/bin/ From 0171e16ba54da747ab3de7dc0abe94df1db3469e Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 22 Feb 2024 11:07:55 -0300 Subject: [PATCH 032/106] Update contracts submodule commit --- .gitmodules | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 53fb816b1ae7..71fef99dc0ba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "contracts"] path = contracts url = https://github.com/LambdaClass/era-contracts.git -branch = update_validium_mode_contracts +branch = feat_validium_mode diff --git a/contracts b/contracts index ceb214b7650c..22e81ea9df4b 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit ceb214b7650c6102703a9b5569a4056fe97a3be4 +Subproject commit 22e81ea9df4bec8ef53f97353da5b915d30f5d39 From 733d3e902ce4d19542d49ef411ef58ae3f8e0346 Mon Sep 17 00:00:00 2001 From: Jordi Date: Thu, 22 Feb 2024 15:13:03 +0100 Subject: [PATCH 033/106] Use serve(default) instead --- core/lib/config/src/configs/chain.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index a1aaca3c5839..67a6843b466b 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -52,10 +52,6 @@ pub enum L1BatchCommitDataGeneratorMode { Validium, } -fn default_l1_batch_commit_data_generator_mode() -> L1BatchCommitDataGeneratorMode { - L1BatchCommitDataGeneratorMode::Rollup -} - #[derive(Debug, Deserialize, Clone, PartialEq, Default)] pub struct StateKeeperConfig { /// The max number of slots for txs in a block before it should be sealed by the slots sealer. @@ -127,7 +123,7 @@ pub struct StateKeeperConfig { /// Number of keys that is processed by enum_index migration in State Keeper each L1 batch. pub enum_index_migration_chunk_size: Option, - #[serde(default = "default_l1_batch_commit_data_generator_mode")] + #[serde(default)] pub l1_batch_commit_data_generator_mode: L1BatchCommitDataGeneratorMode, } From c2c69f1c5875b37c57e4c700941477a0d2edd2d2 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 22 Feb 2024 11:23:40 -0300 Subject: [PATCH 034/106] Update contracts submodule commit --- .gitmodules | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 71fef99dc0ba..9f35d9639867 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "contracts"] path = contracts url = https://github.com/LambdaClass/era-contracts.git -branch = feat_validium_mode +branch = feat_get_rid_of_solpp_need diff --git a/contracts b/contracts index 22e81ea9df4b..9ab2f16841b0 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 22e81ea9df4bec8ef53f97353da5b915d30f5d39 +Subproject commit 9ab2f16841b04e1f35d1646352b99a61a2a741c4 From 66cdefcfd86d5ddd2718f04491f577d6a24161f6 Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Thu, 22 Feb 2024 16:54:51 +0200 Subject: [PATCH 035/106] feat(vm): Add new VM folder (#1208) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Copy `vm_latest`, pasted as `vm_1_4_1`. Replaced all occurrence of `vm_latest` to `vm_1_4_1` inside `vm_1_4_1` folder ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- .../multivm/src/versions/vm_1_4_1/README.md | 44 + .../vm_1_4_1/bootloader_state/l2_block.rs | 87 ++ .../versions/vm_1_4_1/bootloader_state/mod.rs | 8 + .../vm_1_4_1/bootloader_state/snapshot.rs | 25 + .../vm_1_4_1/bootloader_state/state.rs | 295 +++++++ .../versions/vm_1_4_1/bootloader_state/tx.rs | 49 ++ .../vm_1_4_1/bootloader_state/utils.rs | 177 ++++ .../src/versions/vm_1_4_1/constants.rs | 173 ++++ .../vm_1_4_1/implementation/bytecode.rs | 58 ++ .../vm_1_4_1/implementation/execution.rs | 144 ++++ .../versions/vm_1_4_1/implementation/gas.rs | 32 + .../versions/vm_1_4_1/implementation/logs.rs | 76 ++ .../versions/vm_1_4_1/implementation/mod.rs | 7 + .../vm_1_4_1/implementation/snapshots.rs | 91 ++ .../vm_1_4_1/implementation/statistics.rs | 73 ++ .../versions/vm_1_4_1/implementation/tx.rs | 66 ++ core/lib/multivm/src/versions/vm_1_4_1/mod.rs | 36 + .../versions/vm_1_4_1/old_vm/event_sink.rs | 263 ++++++ .../src/versions/vm_1_4_1/old_vm/events.rs | 146 ++++ .../vm_1_4_1/old_vm/history_recorder.rs | 811 ++++++++++++++++++ .../src/versions/vm_1_4_1/old_vm/memory.rs | 327 +++++++ .../src/versions/vm_1_4_1/old_vm/mod.rs | 8 + .../vm_1_4_1/old_vm/oracles/decommitter.rs | 235 +++++ .../versions/vm_1_4_1/old_vm/oracles/mod.rs | 8 + .../vm_1_4_1/old_vm/oracles/precompile.rs | 112 +++ .../src/versions/vm_1_4_1/old_vm/utils.rs | 212 +++++ .../src/versions/vm_1_4_1/oracles/mod.rs | 1 + .../src/versions/vm_1_4_1/oracles/storage.rs | 514 +++++++++++ .../src/versions/vm_1_4_1/tests/block_tip.rs | 284 ++++++ .../src/versions/vm_1_4_1/tests/bootloader.rs | 56 ++ .../vm_1_4_1/tests/bytecode_publishing.rs | 43 + .../versions/vm_1_4_1/tests/call_tracer.rs | 92 ++ .../src/versions/vm_1_4_1/tests/circuits.rs | 69 ++ .../src/versions/vm_1_4_1/tests/default_aa.rs | 78 ++ .../src/versions/vm_1_4_1/tests/gas_limit.rs | 47 + .../vm_1_4_1/tests/get_used_contracts.rs | 109 +++ .../vm_1_4_1/tests/invalid_bytecode.rs | 120 +++ .../vm_1_4_1/tests/is_write_initial.rs | 48 ++ .../vm_1_4_1/tests/l1_tx_execution.rs | 189 ++++ .../src/versions/vm_1_4_1/tests/l2_blocks.rs | 437 ++++++++++ .../src/versions/vm_1_4_1/tests/mod.rs | 23 + .../versions/vm_1_4_1/tests/nonce_holder.rs | 188 ++++ .../versions/vm_1_4_1/tests/precompiles.rs | 136 +++ .../src/versions/vm_1_4_1/tests/refunds.rs | 166 ++++ .../versions/vm_1_4_1/tests/require_eip712.rs | 165 ++++ .../src/versions/vm_1_4_1/tests/rollbacks.rs | 263 ++++++ .../vm_1_4_1/tests/simple_execution.rs | 81 ++ .../vm_1_4_1/tests/tester/inner_state.rs | 131 +++ .../src/versions/vm_1_4_1/tests/tester/mod.rs | 9 + .../tests/tester/transaction_test_info.rs | 217 +++++ .../vm_1_4_1/tests/tester/vm_tester.rs | 298 +++++++ .../vm_1_4_1/tests/tracing_execution_error.rs | 54 ++ .../src/versions/vm_1_4_1/tests/upgrade.rs | 355 ++++++++ .../src/versions/vm_1_4_1/tests/utils.rs | 121 +++ .../vm_1_4_1/tracers/circuits_capacity.rs | 67 ++ .../vm_1_4_1/tracers/circuits_tracer.rs | 233 +++++ .../vm_1_4_1/tracers/default_tracers.rs | 314 +++++++ .../versions/vm_1_4_1/tracers/dispatcher.rs | 126 +++ .../src/versions/vm_1_4_1/tracers/mod.rs | 16 + .../vm_1_4_1/tracers/pubdata_tracer.rs | 238 +++++ .../src/versions/vm_1_4_1/tracers/refunds.rs | 361 ++++++++ .../vm_1_4_1/tracers/result_tracer.rs | 246 ++++++ .../src/versions/vm_1_4_1/tracers/traits.rs | 47 + .../src/versions/vm_1_4_1/tracers/utils.rs | 225 +++++ .../versions/vm_1_4_1/types/internals/mod.rs | 9 + .../vm_1_4_1/types/internals/pubdata.rs | 124 +++ .../vm_1_4_1/types/internals/snapshot.rs | 11 + .../types/internals/transaction_data.rs | 344 ++++++++ .../vm_1_4_1/types/internals/vm_state.rs | 181 ++++ .../src/versions/vm_1_4_1/types/l1_batch.rs | 44 + .../src/versions/vm_1_4_1/types/mod.rs | 2 + .../src/versions/vm_1_4_1/utils/fee.rs | 70 ++ .../src/versions/vm_1_4_1/utils/l2_blocks.rs | 95 ++ .../src/versions/vm_1_4_1/utils/logs.rs | 37 + .../src/versions/vm_1_4_1/utils/mod.rs | 6 + .../src/versions/vm_1_4_1/utils/overhead.rs | 8 + .../vm_1_4_1/utils/transaction_encoding.rs | 16 + core/lib/multivm/src/versions/vm_1_4_1/vm.rs | 211 +++++ 78 files changed, 10888 insertions(+) create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/README.md create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/l2_block.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/snapshot.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/state.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/tx.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/utils.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/constants.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/bytecode.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/gas.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/logs.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/statistics.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/implementation/tx.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/event_sink.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/events.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/history_recorder.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/memory.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/decommitter.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/precompile.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/old_vm/utils.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/oracles/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/oracles/storage.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/block_tip.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/bootloader.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/bytecode_publishing.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/call_tracer.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/circuits.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/default_aa.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/invalid_bytecode.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/is_write_initial.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/l1_tx_execution.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/l2_blocks.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/nonce_holder.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/precompiles.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/refunds.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/require_eip712.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/rollbacks.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/simple_execution.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/tester/inner_state.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/tester/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/tester/transaction_test_info.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/tester/vm_tester.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/tracing_execution_error.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/upgrade.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tests/utils.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_capacity.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_tracer.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/default_tracers.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/dispatcher.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/result_tracer.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/traits.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/tracers/utils.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/types/internals/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/types/internals/pubdata.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/types/internals/snapshot.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/types/internals/vm_state.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/types/l1_batch.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/types/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/utils/l2_blocks.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/utils/logs.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/utils/mod.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/utils/overhead.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/utils/transaction_encoding.rs create mode 100644 core/lib/multivm/src/versions/vm_1_4_1/vm.rs diff --git a/core/lib/multivm/src/versions/vm_1_4_1/README.md b/core/lib/multivm/src/versions/vm_1_4_1/README.md new file mode 100644 index 000000000000..d515df0dfc60 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/README.md @@ -0,0 +1,44 @@ +# VM Crate + +This crate contains code that interacts with the VM (Virtual Machine). The VM itself is in a separate repository +[era-zk_evm][zk_evm_repo_ext]. + +## VM Dependencies + +The VM relies on several subcomponents or traits, such as Memory and Storage. These traits are defined in the `zk_evm` +repository, while their implementations can be found in this crate, such as the storage implementation in +`oracles/storage.rs` and the Memory implementation in `memory.rs`. + +Many of these implementations also support easy rollbacks and history, which is useful when creating a block with +multiple transactions and needing to return the VM to a previous state if a transaction doesn't fit. + +## Running the VM + +To interact with the VM, you must initialize it with `L1BatchEnv`, which represents the initial parameters of the batch, +`SystemEnv`, that represents the system parameters, and a reference to the Storage. To execute a transaction, you have +to push the transaction into the bootloader memory and call the `execute_next_transaction` method. + +### Tracers + +The VM implementation allows for the addition of `Tracers`, which are activated before and after each instruction. This +provides a more in-depth look into the VM, collecting detailed debugging information and logs. More details can be found +in the `tracer/` directory. + +This VM also supports custom tracers. You can call the `inspect_next_transaction` method with a custom tracer and +receive the result of the execution. + +### Bootloader + +In the context of zkEVM, we usually think about transactions. However, from the VM's perspective, it runs a single +program called the bootloader, which internally processes multiple transactions. + +### Rollbacks + +The `VMInstance` in `vm.rs` allows for easy rollbacks. You can save the current state at any moment by calling +`make_snapshot()` and return to that state using `rollback_to_the_latest_snapshot()`. + +This rollback affects all subcomponents, such as memory, storage, and events, and is mainly used if a transaction +doesn't fit in a block. + +[zk_evm_repo]: https://github.com/matter-labs/zk_evm 'internal zk EVM repo' +[zk_evm_repo_ext]: https://github.com/matter-labs/era-zk_evm 'external zk EVM repo' diff --git a/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/l2_block.rs b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/l2_block.rs new file mode 100644 index 000000000000..65b60df809c4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/l2_block.rs @@ -0,0 +1,87 @@ +use std::cmp::Ordering; + +use zksync_types::{MiniblockNumber, H256}; +use zksync_utils::concat_and_hash; + +use crate::{ + interface::{L2Block, L2BlockEnv}, + vm_1_4_1::{ + bootloader_state::{snapshot::L2BlockSnapshot, tx::BootloaderTx}, + utils::l2_blocks::l2_block_hash, + }, +}; + +const EMPTY_TXS_ROLLING_HASH: H256 = H256::zero(); + +#[derive(Debug, Clone)] +pub(crate) struct BootloaderL2Block { + pub(crate) number: u32, + pub(crate) timestamp: u64, + pub(crate) txs_rolling_hash: H256, // The rolling hash of all the transactions in the miniblock + pub(crate) prev_block_hash: H256, + // Number of the first L2 block tx in L1 batch + pub(crate) first_tx_index: usize, + pub(crate) max_virtual_blocks_to_create: u32, + pub(crate) txs: Vec, +} + +impl BootloaderL2Block { + pub(crate) fn new(l2_block: L2BlockEnv, first_tx_place: usize) -> Self { + Self { + number: l2_block.number, + timestamp: l2_block.timestamp, + txs_rolling_hash: EMPTY_TXS_ROLLING_HASH, + prev_block_hash: l2_block.prev_block_hash, + first_tx_index: first_tx_place, + max_virtual_blocks_to_create: l2_block.max_virtual_blocks_to_create, + txs: vec![], + } + } + + pub(super) fn push_tx(&mut self, tx: BootloaderTx) { + self.update_rolling_hash(tx.hash); + self.txs.push(tx) + } + + pub(crate) fn get_hash(&self) -> H256 { + l2_block_hash( + MiniblockNumber(self.number), + self.timestamp, + self.prev_block_hash, + self.txs_rolling_hash, + ) + } + + fn update_rolling_hash(&mut self, tx_hash: H256) { + self.txs_rolling_hash = concat_and_hash(self.txs_rolling_hash, tx_hash) + } + + pub(crate) fn interim_version(&self) -> BootloaderL2Block { + let mut interim = self.clone(); + interim.max_virtual_blocks_to_create = 0; + interim + } + + pub(crate) fn make_snapshot(&self) -> L2BlockSnapshot { + L2BlockSnapshot { + txs_rolling_hash: self.txs_rolling_hash, + txs_len: self.txs.len(), + } + } + + pub(crate) fn apply_snapshot(&mut self, snapshot: L2BlockSnapshot) { + self.txs_rolling_hash = snapshot.txs_rolling_hash; + match self.txs.len().cmp(&snapshot.txs_len) { + Ordering::Greater => self.txs.truncate(snapshot.txs_len), + Ordering::Less => panic!("Applying snapshot from future is not supported"), + Ordering::Equal => {} + } + } + pub(crate) fn l2_block(&self) -> L2Block { + L2Block { + number: self.number, + timestamp: self.timestamp, + hash: self.get_hash(), + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/mod.rs new file mode 100644 index 000000000000..73830de2759b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/mod.rs @@ -0,0 +1,8 @@ +mod l2_block; +mod snapshot; +mod state; +mod tx; + +pub(crate) mod utils; +pub(crate) use snapshot::BootloaderStateSnapshot; +pub use state::BootloaderState; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/snapshot.rs b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/snapshot.rs new file mode 100644 index 000000000000..8f1cec3cb7f1 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/snapshot.rs @@ -0,0 +1,25 @@ +use zksync_types::H256; + +#[derive(Debug, Clone)] +pub(crate) struct BootloaderStateSnapshot { + /// ID of the next transaction to be executed. + pub(crate) tx_to_execute: usize, + /// Stored L2 blocks in bootloader memory + pub(crate) l2_blocks_len: usize, + /// Snapshot of the last L2 block. Only this block could be changed during the rollback + pub(crate) last_l2_block: L2BlockSnapshot, + /// The number of 32-byte words spent on the already included compressed bytecodes. + pub(crate) compressed_bytecodes_encoding: usize, + /// Current offset of the free space in the bootloader memory. + pub(crate) free_tx_offset: usize, + /// Whether the pubdata information has been provided already + pub(crate) is_pubdata_information_provided: bool, +} + +#[derive(Debug, Clone)] +pub(crate) struct L2BlockSnapshot { + /// The rolling hash of all the transactions in the miniblock + pub(crate) txs_rolling_hash: H256, + /// The number of transactions in the last L2 block + pub(crate) txs_len: usize, +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/state.rs b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/state.rs new file mode 100644 index 000000000000..9a1a727aab39 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/state.rs @@ -0,0 +1,295 @@ +use std::cmp::Ordering; + +use once_cell::sync::OnceCell; +use zksync_types::{L2ChainId, U256}; +use zksync_utils::bytecode::CompressedBytecodeInfo; + +use super::{tx::BootloaderTx, utils::apply_pubdata_to_memory}; +use crate::{ + interface::{BootloaderMemory, L2BlockEnv, TxExecutionMode}, + vm_1_4_1::{ + bootloader_state::{ + l2_block::BootloaderL2Block, + snapshot::BootloaderStateSnapshot, + utils::{apply_l2_block, apply_tx_to_memory}, + }, + constants::TX_DESCRIPTION_OFFSET, + types::internals::{PubdataInput, TransactionData}, + utils::l2_blocks::assert_next_block, + }, +}; + +/// Intermediate bootloader-related VM state. +/// +/// Required to process transactions one by one (since we intercept the VM execution to execute +/// transactions and add new ones to the memory on the fly). +/// Keeps tracking everything related to the bootloader memory and can restore the whole memory. +/// +/// +/// Serves two purposes: +/// - Tracks where next tx should be pushed to in the bootloader memory. +/// - Tracks which transaction should be executed next. +#[derive(Debug, Clone)] +pub struct BootloaderState { + /// ID of the next transaction to be executed. + /// See the structure doc-comment for a better explanation of purpose. + tx_to_execute: usize, + /// Stored txs in bootloader memory + l2_blocks: Vec, + /// The number of 32-byte words spent on the already included compressed bytecodes. + compressed_bytecodes_encoding: usize, + /// Initial memory of bootloader + initial_memory: BootloaderMemory, + /// Mode of txs for execution, it can be changed once per vm lunch + execution_mode: TxExecutionMode, + /// Current offset of the free space in the bootloader memory. + free_tx_offset: usize, + /// Information about the the pubdata that will be needed to supply to the L1Messenger + pubdata_information: OnceCell, +} + +impl BootloaderState { + pub(crate) fn new( + execution_mode: TxExecutionMode, + initial_memory: BootloaderMemory, + first_l2_block: L2BlockEnv, + ) -> Self { + let l2_block = BootloaderL2Block::new(first_l2_block, 0); + Self { + tx_to_execute: 0, + compressed_bytecodes_encoding: 0, + l2_blocks: vec![l2_block], + initial_memory, + execution_mode, + free_tx_offset: 0, + pubdata_information: Default::default(), + } + } + + pub(crate) fn set_refund_for_current_tx(&mut self, refund: u32) { + let current_tx = self.current_tx(); + // We can't set the refund for the latest tx or using the latest l2_block for fining tx + // Because we can fill the whole batch first and then execute txs one by one + let tx = self.find_tx_mut(current_tx); + tx.refund = refund; + } + + pub(crate) fn set_pubdata_input(&mut self, info: PubdataInput) { + self.pubdata_information + .set(info) + .expect("Pubdata information is already set"); + } + + pub(crate) fn start_new_l2_block(&mut self, l2_block: L2BlockEnv) { + let last_block = self.last_l2_block(); + assert!( + !last_block.txs.is_empty(), + "Can not create new miniblocks on top of empty ones" + ); + assert_next_block(&last_block.l2_block(), &l2_block); + self.push_l2_block(l2_block); + } + + /// This method bypass sanity checks and should be used carefully. + pub(crate) fn push_l2_block(&mut self, l2_block: L2BlockEnv) { + self.l2_blocks + .push(BootloaderL2Block::new(l2_block, self.free_tx_index())) + } + + pub(crate) fn push_tx( + &mut self, + tx: TransactionData, + predefined_overhead: u32, + predefined_refund: u32, + compressed_bytecodes: Vec, + trusted_ergs_limit: U256, + chain_id: L2ChainId, + ) -> BootloaderMemory { + let tx_offset = self.free_tx_offset(); + let bootloader_tx = BootloaderTx::new( + tx, + predefined_refund, + predefined_overhead, + trusted_ergs_limit, + compressed_bytecodes, + tx_offset, + chain_id, + ); + + let mut memory = vec![]; + let compressed_bytecode_size = apply_tx_to_memory( + &mut memory, + &bootloader_tx, + self.last_l2_block(), + self.free_tx_index(), + self.free_tx_offset(), + self.compressed_bytecodes_encoding, + self.execution_mode, + self.last_l2_block().txs.is_empty(), + ); + self.compressed_bytecodes_encoding += compressed_bytecode_size; + self.free_tx_offset = tx_offset + bootloader_tx.encoded_len(); + self.last_mut_l2_block().push_tx(bootloader_tx); + memory + } + + pub(crate) fn last_l2_block(&self) -> &BootloaderL2Block { + self.l2_blocks.last().unwrap() + } + pub(crate) fn get_pubdata_information(&self) -> &PubdataInput { + self.pubdata_information + .get() + .expect("Pubdata information is not set") + } + + fn last_mut_l2_block(&mut self) -> &mut BootloaderL2Block { + self.l2_blocks.last_mut().unwrap() + } + + /// Apply all bootloader transaction to the initial memory + pub(crate) fn bootloader_memory(&self) -> BootloaderMemory { + let mut initial_memory = self.initial_memory.clone(); + let mut offset = 0; + let mut compressed_bytecodes_offset = 0; + let mut tx_index = 0; + for l2_block in &self.l2_blocks { + for (num, tx) in l2_block.txs.iter().enumerate() { + let compressed_bytecodes_size = apply_tx_to_memory( + &mut initial_memory, + tx, + l2_block, + tx_index, + offset, + compressed_bytecodes_offset, + self.execution_mode, + num == 0, + ); + offset += tx.encoded_len(); + compressed_bytecodes_offset += compressed_bytecodes_size; + tx_index += 1; + } + if l2_block.txs.is_empty() { + apply_l2_block(&mut initial_memory, l2_block, tx_index) + } + } + + let pubdata_information = self + .pubdata_information + .clone() + .into_inner() + .expect("Empty pubdata information"); + + apply_pubdata_to_memory(&mut initial_memory, pubdata_information); + initial_memory + } + + fn free_tx_offset(&self) -> usize { + self.free_tx_offset + } + + pub(crate) fn free_tx_index(&self) -> usize { + let l2_block = self.last_l2_block(); + l2_block.first_tx_index + l2_block.txs.len() + } + + pub(crate) fn get_last_tx_compressed_bytecodes(&self) -> Vec { + if let Some(tx) = self.last_l2_block().txs.last() { + tx.compressed_bytecodes.clone() + } else { + vec![] + } + } + + /// Returns the id of current tx + pub(crate) fn current_tx(&self) -> usize { + self.tx_to_execute + .checked_sub(1) + .expect("There are no current tx to execute") + } + + /// Returns the ID of the next transaction to be executed and increments the local transaction counter. + pub(crate) fn move_tx_to_execute_pointer(&mut self) -> usize { + assert!( + self.tx_to_execute < self.free_tx_index(), + "Attempt to execute tx that was not pushed to memory. Tx ID: {}, txs in bootloader: {}", + self.tx_to_execute, + self.free_tx_index() + ); + + let old = self.tx_to_execute; + self.tx_to_execute += 1; + old + } + + /// Get offset of tx description + pub(crate) fn get_tx_description_offset(&self, tx_index: usize) -> usize { + TX_DESCRIPTION_OFFSET + self.find_tx(tx_index).offset + } + + pub(crate) fn insert_fictive_l2_block(&mut self) -> &BootloaderL2Block { + let block = self.last_l2_block(); + if !block.txs.is_empty() { + self.start_new_l2_block(L2BlockEnv { + timestamp: block.timestamp + 1, + number: block.number + 1, + prev_block_hash: block.get_hash(), + max_virtual_blocks_to_create: 1, + }); + } + self.last_l2_block() + } + + fn find_tx(&self, tx_index: usize) -> &BootloaderTx { + for block in self.l2_blocks.iter().rev() { + if tx_index >= block.first_tx_index { + return &block.txs[tx_index - block.first_tx_index]; + } + } + panic!("The tx with index {} must exist", tx_index) + } + + fn find_tx_mut(&mut self, tx_index: usize) -> &mut BootloaderTx { + for block in self.l2_blocks.iter_mut().rev() { + if tx_index >= block.first_tx_index { + return &mut block.txs[tx_index - block.first_tx_index]; + } + } + panic!("The tx with index {} must exist", tx_index) + } + + pub(crate) fn get_snapshot(&self) -> BootloaderStateSnapshot { + BootloaderStateSnapshot { + tx_to_execute: self.tx_to_execute, + l2_blocks_len: self.l2_blocks.len(), + last_l2_block: self.last_l2_block().make_snapshot(), + compressed_bytecodes_encoding: self.compressed_bytecodes_encoding, + free_tx_offset: self.free_tx_offset, + is_pubdata_information_provided: self.pubdata_information.get().is_some(), + } + } + + pub(crate) fn apply_snapshot(&mut self, snapshot: BootloaderStateSnapshot) { + self.tx_to_execute = snapshot.tx_to_execute; + self.compressed_bytecodes_encoding = snapshot.compressed_bytecodes_encoding; + self.free_tx_offset = snapshot.free_tx_offset; + match self.l2_blocks.len().cmp(&snapshot.l2_blocks_len) { + Ordering::Greater => self.l2_blocks.truncate(snapshot.l2_blocks_len), + Ordering::Less => panic!("Applying snapshot from future is not supported"), + Ordering::Equal => {} + } + self.last_mut_l2_block() + .apply_snapshot(snapshot.last_l2_block); + + if !snapshot.is_pubdata_information_provided { + self.pubdata_information = Default::default(); + } else { + // Under the correct usage of the snapshots of the bootloader state, + // this assertion should never fail, i.e. since the pubdata information + // can be set only once. However, we have this assertion just in case. + assert!( + self.pubdata_information.get().is_some(), + "Snapshot with no pubdata can not rollback to snapshot with one" + ); + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/tx.rs b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/tx.rs new file mode 100644 index 000000000000..f82f34a7b0e7 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/tx.rs @@ -0,0 +1,49 @@ +use zksync_types::{L2ChainId, H256, U256}; +use zksync_utils::bytecode::CompressedBytecodeInfo; + +use crate::vm_1_4_1::types::internals::TransactionData; + +/// Information about tx necessary for execution in bootloader. +#[derive(Debug, Clone)] +pub(crate) struct BootloaderTx { + pub(crate) hash: H256, + /// Encoded transaction + pub(crate) encoded: Vec, + /// Compressed bytecodes, which has been published during this transaction + pub(crate) compressed_bytecodes: Vec, + /// Refunds for this transaction + pub(crate) refund: u32, + /// Gas overhead + pub(crate) gas_overhead: u32, + /// Gas Limit for this transaction. It can be different from the gas limit inside the transaction + pub(crate) trusted_gas_limit: U256, + /// Offset of the tx in bootloader memory + pub(crate) offset: usize, +} + +impl BootloaderTx { + pub(super) fn new( + tx: TransactionData, + predefined_refund: u32, + predefined_overhead: u32, + trusted_gas_limit: U256, + compressed_bytecodes: Vec, + offset: usize, + chain_id: L2ChainId, + ) -> Self { + let hash = tx.tx_hash(chain_id); + Self { + hash, + encoded: tx.into_tokens(), + compressed_bytecodes, + refund: predefined_refund, + gas_overhead: predefined_overhead, + trusted_gas_limit, + offset, + } + } + + pub(super) fn encoded_len(&self) -> usize { + self.encoded.len() + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/utils.rs b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/utils.rs new file mode 100644 index 000000000000..d203542b16b4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/bootloader_state/utils.rs @@ -0,0 +1,177 @@ +use zksync_types::{ethabi, U256}; +use zksync_utils::{bytecode::CompressedBytecodeInfo, bytes_to_be_words, h256_to_u256}; + +use super::tx::BootloaderTx; +use crate::{ + interface::{BootloaderMemory, TxExecutionMode}, + vm_1_4_1::{ + bootloader_state::l2_block::BootloaderL2Block, + constants::{ + BOOTLOADER_TX_DESCRIPTION_OFFSET, BOOTLOADER_TX_DESCRIPTION_SIZE, + COMPRESSED_BYTECODES_OFFSET, OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET, + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS, OPERATOR_REFUNDS_OFFSET, + TX_DESCRIPTION_OFFSET, TX_OPERATOR_L2_BLOCK_INFO_OFFSET, + TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO, TX_OVERHEAD_OFFSET, TX_TRUSTED_GAS_LIMIT_OFFSET, + }, + types::internals::PubdataInput, + }, +}; + +pub(super) fn get_memory_for_compressed_bytecodes( + compressed_bytecodes: &[CompressedBytecodeInfo], +) -> Vec { + let memory_addition: Vec<_> = compressed_bytecodes + .iter() + .flat_map(|x| x.encode_call()) + .collect(); + + bytes_to_be_words(memory_addition) +} + +#[allow(clippy::too_many_arguments)] +pub(super) fn apply_tx_to_memory( + memory: &mut BootloaderMemory, + bootloader_tx: &BootloaderTx, + bootloader_l2_block: &BootloaderL2Block, + tx_index: usize, + tx_offset: usize, + compressed_bytecodes_size: usize, + execution_mode: TxExecutionMode, + start_new_l2_block: bool, +) -> usize { + let bootloader_description_offset = + BOOTLOADER_TX_DESCRIPTION_OFFSET + BOOTLOADER_TX_DESCRIPTION_SIZE * tx_index; + let tx_description_offset = TX_DESCRIPTION_OFFSET + tx_offset; + + memory.push(( + bootloader_description_offset, + assemble_tx_meta(execution_mode, true), + )); + + memory.push(( + bootloader_description_offset + 1, + U256::from_big_endian(&(32 * tx_description_offset).to_be_bytes()), + )); + + let refund_offset = OPERATOR_REFUNDS_OFFSET + tx_index; + memory.push((refund_offset, bootloader_tx.refund.into())); + + let overhead_offset = TX_OVERHEAD_OFFSET + tx_index; + memory.push((overhead_offset, bootloader_tx.gas_overhead.into())); + + let trusted_gas_limit_offset = TX_TRUSTED_GAS_LIMIT_OFFSET + tx_index; + memory.push((trusted_gas_limit_offset, bootloader_tx.trusted_gas_limit)); + + memory.extend( + (tx_description_offset..tx_description_offset + bootloader_tx.encoded_len()) + .zip(bootloader_tx.encoded.clone()), + ); + + let bootloader_l2_block = if start_new_l2_block { + bootloader_l2_block.clone() + } else { + bootloader_l2_block.interim_version() + }; + apply_l2_block(memory, &bootloader_l2_block, tx_index); + + // Note, +1 is moving for pointer + let compressed_bytecodes_offset = COMPRESSED_BYTECODES_OFFSET + 1 + compressed_bytecodes_size; + + let encoded_compressed_bytecodes = + get_memory_for_compressed_bytecodes(&bootloader_tx.compressed_bytecodes); + let compressed_bytecodes_encoding = encoded_compressed_bytecodes.len(); + + memory.extend( + (compressed_bytecodes_offset + ..compressed_bytecodes_offset + encoded_compressed_bytecodes.len()) + .zip(encoded_compressed_bytecodes), + ); + compressed_bytecodes_encoding +} + +pub(crate) fn apply_l2_block( + memory: &mut BootloaderMemory, + bootloader_l2_block: &BootloaderL2Block, + txs_index: usize, +) { + // Since L2 block information start from the `TX_OPERATOR_L2_BLOCK_INFO_OFFSET` and each + // L2 block info takes `TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO` slots, the position where the L2 block info + // for this transaction needs to be written is: + + let block_position = + TX_OPERATOR_L2_BLOCK_INFO_OFFSET + txs_index * TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO; + + memory.extend(vec![ + (block_position, bootloader_l2_block.number.into()), + (block_position + 1, bootloader_l2_block.timestamp.into()), + ( + block_position + 2, + h256_to_u256(bootloader_l2_block.prev_block_hash), + ), + ( + block_position + 3, + bootloader_l2_block.max_virtual_blocks_to_create.into(), + ), + ]) +} + +pub(crate) fn apply_pubdata_to_memory( + memory: &mut BootloaderMemory, + pubdata_information: PubdataInput, +) { + // Skipping two slots as they will be filled by the bootloader itself: + // - One slot is for the selector of the call to the L1Messenger. + // - The other slot is for the 0x20 offset for the calldata. + let l1_messenger_pubdata_start_slot = OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET + 2; + + // Need to skip first word as it represents array offset + // while bootloader expects only [len || data] + let pubdata = ethabi::encode(&[ethabi::Token::Bytes( + pubdata_information.build_pubdata(true), + )])[32..] + .to_vec(); + + assert!( + pubdata.len() / 32 <= OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS - 2, + "The encoded pubdata is too big" + ); + + pubdata + .chunks(32) + .enumerate() + .for_each(|(slot_offset, value)| { + memory.push(( + l1_messenger_pubdata_start_slot + slot_offset, + U256::from(value), + )) + }); +} + +/// Forms a word that contains meta information for the transaction execution. +/// +/// # Current layout +/// +/// - 0 byte (MSB): server-side tx execution mode +/// In the server, we may want to execute different parts of the transaction in the different context +/// For example, when checking validity, we don't want to actually execute transaction and have side effects. +/// +/// Possible values: +/// - 0x00: validate & execute (normal mode) +/// - 0x02: execute but DO NOT validate +/// +/// - 31 byte (LSB): whether to execute transaction or not (at all). +pub(super) fn assemble_tx_meta(execution_mode: TxExecutionMode, execute_tx: bool) -> U256 { + let mut output = [0u8; 32]; + + // Set 0 byte (execution mode) + output[0] = match execution_mode { + TxExecutionMode::VerifyExecute => 0x00, + TxExecutionMode::EstimateFee { .. } => 0x00, + TxExecutionMode::EthCall { .. } => 0x02, + }; + + // Set 31 byte (marker for tx execution) + output[31] = u8::from(execute_tx); + + U256::from_big_endian(&output) +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/constants.rs b/core/lib/multivm/src/versions/vm_1_4_1/constants.rs new file mode 100644 index 000000000000..7f656de562a4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/constants.rs @@ -0,0 +1,173 @@ +use zk_evm_1_4_1::aux_structures::MemoryPage; +pub use zk_evm_1_4_1::zkevm_opcode_defs::system_params::{ + ERGS_PER_CIRCUIT, INITIAL_STORAGE_WRITE_PUBDATA_BYTES, MAX_PUBDATA_PER_BLOCK, +}; +use zksync_system_constants::{MAX_L2_TX_GAS_LIMIT, MAX_NEW_FACTORY_DEPS}; + +use crate::vm_1_4_1::old_vm::utils::heap_page_from_base; + +/// The amount of ergs to be reserved at the end of the batch to ensure that it has enough ergs to verify compression, etc. +pub(crate) const BOOTLOADER_BATCH_TIP_OVERHEAD: u32 = 80_000_000; + +/// The size of the bootloader memory in bytes which is used by the protocol. +/// While the maximal possible size is a lot higher, we restrict ourselves to a certain limit to reduce +/// the requirements on RAM. +/// In this version of the VM the used bootloader memory bytes has increased from `2^24`` to `24_000_000`. +pub(crate) const USED_BOOTLOADER_MEMORY_BYTES: usize = 24_000_000; +pub(crate) const USED_BOOTLOADER_MEMORY_WORDS: usize = USED_BOOTLOADER_MEMORY_BYTES / 32; + +// This the number of pubdata such that it should be always possible to publish +// from a single transaction. Note, that these pubdata bytes include only bytes that are +// to be published inside the body of transaction (i.e. excluding of factory deps). +pub(crate) const GUARANTEED_PUBDATA_PER_L1_BATCH: u64 = 2500; + +// The users should always be able to provide `MAX_GAS_PER_PUBDATA_BYTE` gas per pubdata in their +// transactions so that they are able to send at least `GUARANTEED_PUBDATA_PER_L1_BATCH` bytes per +// transaction. +pub(crate) const MAX_GAS_PER_PUBDATA_BYTE: u64 = + MAX_L2_TX_GAS_LIMIT / GUARANTEED_PUBDATA_PER_L1_BATCH; + +// The maximal number of transactions in a single batch. +// In this version of the VM the limit has been increased from `1024` to to `10000`. +pub(crate) const MAX_TXS_IN_BATCH: usize = 10000; + +/// Max cycles for a single transaction. +pub const MAX_CYCLES_FOR_TX: u32 = u32::MAX; + +/// The first 32 slots are reserved for debugging purposes +pub(crate) const DEBUG_SLOTS_OFFSET: usize = 8; +pub(crate) const DEBUG_FIRST_SLOTS: usize = 32; + +/// The next 33 slots are reserved for dealing with the paymaster context (1 slot for storing length + 32 slots for storing the actual context). +pub(crate) const PAYMASTER_CONTEXT_SLOTS: usize = 32 + 1; +/// The next PAYMASTER_CONTEXT_SLOTS + 7 slots free slots are needed before each tx, so that the +/// postOp operation could be encoded correctly. +pub(crate) const MAX_POSTOP_SLOTS: usize = PAYMASTER_CONTEXT_SLOTS + 7; + +/// Slots used to store the current L2 transaction's hash and the hash recommended +/// to be used for signing the transaction's content. +const CURRENT_L2_TX_HASHES_SLOTS: usize = 2; + +/// Slots used to store the calldata for the KnownCodesStorage to mark new factory +/// dependencies as known ones. Besides the slots for the new factory dependencies themselves +/// another 4 slots are needed for: selector, marker of whether the user should pay for the pubdata, +/// the offset for the encoding of the array as well as the length of the array. +const NEW_FACTORY_DEPS_RESERVED_SLOTS: usize = MAX_NEW_FACTORY_DEPS + 4; + +/// The operator can provide for each transaction the proposed minimal refund +pub(crate) const OPERATOR_REFUNDS_SLOTS: usize = MAX_TXS_IN_BATCH; + +pub(crate) const OPERATOR_REFUNDS_OFFSET: usize = DEBUG_SLOTS_OFFSET + + DEBUG_FIRST_SLOTS + + PAYMASTER_CONTEXT_SLOTS + + CURRENT_L2_TX_HASHES_SLOTS + + NEW_FACTORY_DEPS_RESERVED_SLOTS; + +pub(crate) const TX_OVERHEAD_OFFSET: usize = OPERATOR_REFUNDS_OFFSET + OPERATOR_REFUNDS_SLOTS; +pub(crate) const TX_OVERHEAD_SLOTS: usize = MAX_TXS_IN_BATCH; + +pub(crate) const TX_TRUSTED_GAS_LIMIT_OFFSET: usize = TX_OVERHEAD_OFFSET + TX_OVERHEAD_SLOTS; +pub(crate) const TX_TRUSTED_GAS_LIMIT_SLOTS: usize = MAX_TXS_IN_BATCH; + +pub(crate) const COMPRESSED_BYTECODES_SLOTS: usize = 32768; + +pub(crate) const PRIORITY_TXS_L1_DATA_OFFSET: usize = + COMPRESSED_BYTECODES_OFFSET + COMPRESSED_BYTECODES_SLOTS; +pub(crate) const PRIORITY_TXS_L1_DATA_SLOTS: usize = 2; + +pub const OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET: usize = + PRIORITY_TXS_L1_DATA_OFFSET + PRIORITY_TXS_L1_DATA_SLOTS; + +/// One of "worst case" scenarios for the number of state diffs in a batch is when 120kb of pubdata is spent +/// on repeated writes, that are all zeroed out. In this case, the number of diffs is 120k / 5 = 24k. This means that they will have +/// accommodate 6528000 bytes of calldata for the uncompressed state diffs. Adding 120k on top leaves us with +/// roughly 6650000 bytes needed for calldata. 207813 slots are needed to accommodate this amount of data. +/// We round up to 208000 slots just in case. +/// +/// In theory though much more calldata could be used (if for instance 1 byte is used for enum index). It is the responsibility of the +/// operator to ensure that it can form the correct calldata for the L1Messenger. +pub(crate) const OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS: usize = 208000; + +pub(crate) const BOOTLOADER_TX_DESCRIPTION_OFFSET: usize = + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_OFFSET + OPERATOR_PROVIDED_L1_MESSENGER_PUBDATA_SLOTS; + +/// The size of the bootloader memory dedicated to the encodings of transactions +pub(crate) const BOOTLOADER_TX_ENCODING_SPACE: u32 = + (USED_BOOTLOADER_MEMORY_WORDS - TX_DESCRIPTION_OFFSET - MAX_TXS_IN_BATCH) as u32; + +// Size of the bootloader tx description in words +pub(crate) const BOOTLOADER_TX_DESCRIPTION_SIZE: usize = 2; + +/// The actual descriptions of transactions should start after the minor descriptions and a MAX_POSTOP_SLOTS +/// free slots to allow postOp encoding. +pub(crate) const TX_DESCRIPTION_OFFSET: usize = BOOTLOADER_TX_DESCRIPTION_OFFSET + + BOOTLOADER_TX_DESCRIPTION_SIZE * MAX_TXS_IN_BATCH + + MAX_POSTOP_SLOTS; + +pub(crate) const TX_GAS_LIMIT_OFFSET: usize = 4; + +const INITIAL_BASE_PAGE: u32 = 8; +pub const BOOTLOADER_HEAP_PAGE: u32 = heap_page_from_base(MemoryPage(INITIAL_BASE_PAGE)).0; + +/// VM Hooks are used for communication between bootloader and tracers. +/// The 'type' / 'opcode' is put into VM_HOOK_POSITION slot, +/// and VM_HOOKS_PARAMS_COUNT parameters (each 32 bytes) are put in the slots before. +/// So the layout looks like this: +/// `[param 0][param 1][vmhook opcode]` +pub const VM_HOOK_POSITION: u32 = RESULT_SUCCESS_FIRST_SLOT - 1; +pub const VM_HOOK_PARAMS_COUNT: u32 = 2; +pub const VM_HOOK_PARAMS_START_POSITION: u32 = VM_HOOK_POSITION - VM_HOOK_PARAMS_COUNT; + +/// Arbitrary space in memory closer to the end of the page +pub const RESULT_SUCCESS_FIRST_SLOT: u32 = + ((USED_BOOTLOADER_MEMORY_BYTES as u32) - (MAX_TXS_IN_BATCH as u32) * 32) / 32; + +/// How many gas bootloader is allowed to spend within one block. +/// Note that this value doesn't correspond to the gas limit of any particular transaction +/// (except for the fact that, of course, gas limit for each transaction should be <= `BLOCK_GAS_LIMIT`). +pub const BLOCK_GAS_LIMIT: u32 = + zk_evm_1_4_1::zkevm_opcode_defs::system_params::VM_INITIAL_FRAME_ERGS; + +/// How many gas is allowed to spend on a single transaction in eth_call method +pub const ETH_CALL_GAS_LIMIT: u32 = MAX_L2_TX_GAS_LIMIT as u32; + +/// ID of the transaction from L1 +pub const L1_TX_TYPE: u8 = 255; + +pub(crate) const TX_OPERATOR_L2_BLOCK_INFO_OFFSET: usize = + TX_TRUSTED_GAS_LIMIT_OFFSET + TX_TRUSTED_GAS_LIMIT_SLOTS; + +pub(crate) const TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO: usize = 4; +pub(crate) const TX_OPERATOR_L2_BLOCK_INFO_SLOTS: usize = + (MAX_TXS_IN_BATCH + 1) * TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO; + +pub(crate) const COMPRESSED_BYTECODES_OFFSET: usize = + TX_OPERATOR_L2_BLOCK_INFO_OFFSET + TX_OPERATOR_L2_BLOCK_INFO_SLOTS; + +/// The maximal gas limit that gets passed into an L1->L2 transaction. +/// +/// It is equal to the `MAX_GAS_PER_TRANSACTION` in the bootloader. +/// We need to limit the number of gas that can be passed into the L1->L2 transaction due to the fact +/// that unlike L2 transactions they can not be rejected by the operator and must be executed. In turn, +/// this means that if a transaction spends more than `MAX_GAS_PER_TRANSACTION`, it use up all the limited resources of a batch. +/// +/// It the gas limit cap on Mailbox for a priority transactions should generally be low enough to never cross that boundary, since +/// artificially limiting the gas price is bad UX. However, during the transition between the pre-1.4.1 fee model and the 1.4.1 one, +/// we need to process such transactions somehow. +pub(crate) const PRIORITY_TX_MAX_GAS_LIMIT: usize = 80_000_000; + +/// The amount of gas to be charged for occupying a single slot of a transaction. +/// It is roughly equal to `80kk/MAX_TRANSACTIONS_PER_BATCH`, i.e. how many gas would an L1->L2 transaction +/// need to pay to compensate for the batch being closed. +/// While the derived formula is used for the worst case for L1->L2 transaction, it suits L2 transactions as well +/// and serves to compensate the operator for the fact that they need to process the transaction. In case batches start +/// getting often sealed due to the slot limit being reached, the L2 fair gas price will be increased. +pub(crate) const TX_SLOT_OVERHEAD_GAS: u32 = 10_000; + +/// The amount of gas to be charged for occupying a single byte of the bootloader's memory. +/// It is roughly equal to `80kk/BOOTLOADER_MEMORY_FOR_TXS`, i.e. how many gas would an L1->L2 transaction +/// need to pay to compensate for the batch being closed. +/// While the derived formula is used for the worst case for L1->L2 transaction, it suits L2 transactions as well +/// and serves to compensate the operator for the fact that they need to fill up the bootloader memory. In case batches start +/// getting often sealed due to the memory limit being reached, the L2 fair gas price will be increased. +pub(crate) const TX_MEMORY_OVERHEAD_GAS: u32 = 10; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/bytecode.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/bytecode.rs new file mode 100644 index 000000000000..73473e225bd4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/bytecode.rs @@ -0,0 +1,58 @@ +use itertools::Itertools; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::U256; +use zksync_utils::{ + bytecode::{compress_bytecode, hash_bytecode, CompressedBytecodeInfo}, + bytes_to_be_words, +}; + +use crate::{interface::VmInterface, vm_1_4_1::Vm, HistoryMode}; + +impl Vm { + /// Checks the last transaction has successfully published compressed bytecodes and returns `true` if there is at least one is still unknown. + pub(crate) fn has_unpublished_bytecodes(&mut self) -> bool { + self.get_last_tx_compressed_bytecodes().iter().any(|info| { + !self + .state + .storage + .storage + .get_ptr() + .borrow_mut() + .is_bytecode_known(&hash_bytecode(&info.original)) + }) + } +} + +/// Converts bytecode to tokens and hashes it. +pub(crate) fn bytecode_to_factory_dep(bytecode: Vec) -> (U256, Vec) { + let bytecode_hash = hash_bytecode(&bytecode); + let bytecode_hash = U256::from_big_endian(bytecode_hash.as_bytes()); + + let bytecode_words = bytes_to_be_words(bytecode); + + (bytecode_hash, bytecode_words) +} + +pub(crate) fn compress_bytecodes( + bytecodes: &[Vec], + storage: StoragePtr, +) -> Vec { + bytecodes + .iter() + .enumerate() + .sorted_by_key(|(_idx, dep)| *dep) + .dedup_by(|x, y| x.1 == y.1) + .filter(|(_idx, dep)| !storage.borrow_mut().is_bytecode_known(&hash_bytecode(dep))) + .sorted_by_key(|(idx, _dep)| *idx) + .filter_map(|(_idx, dep)| { + let compressed_bytecode = compress_bytecode(dep); + + compressed_bytecode + .ok() + .map(|compressed| CompressedBytecodeInfo { + original: dep.clone(), + compressed, + }) + }) + .collect() +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs new file mode 100644 index 000000000000..2378bb905d4a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/execution.rs @@ -0,0 +1,144 @@ +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_state::WriteStorage; + +use crate::{ + interface::{ + types::tracer::{TracerExecutionStatus, VmExecutionStopReason}, + VmExecutionMode, VmExecutionResultAndLogs, VmInterface, + }, + vm_1_4_1::{ + old_vm::utils::{vm_may_have_ended_inner, VmExecutionResult}, + tracers::{ + circuits_capacity::circuit_statistic_from_cycles, dispatcher::TracerDispatcher, + DefaultExecutionTracer, PubdataTracer, RefundsTracer, + }, + vm::Vm, + }, + HistoryMode, +}; + +impl Vm { + pub(crate) fn inspect_inner( + &mut self, + dispatcher: TracerDispatcher, + execution_mode: VmExecutionMode, + custom_pubdata_tracer: Option>, + ) -> VmExecutionResultAndLogs { + let mut enable_refund_tracer = false; + if let VmExecutionMode::OneTx = execution_mode { + // Move the pointer to the next transaction + self.bootloader_state.move_tx_to_execute_pointer(); + enable_refund_tracer = true; + } + + let (_, result) = self.inspect_and_collect_results( + dispatcher, + execution_mode, + enable_refund_tracer, + custom_pubdata_tracer, + ); + result + } + + /// Execute VM with given traces until the stop reason is reached. + /// Collect the result from the default tracers. + fn inspect_and_collect_results( + &mut self, + dispatcher: TracerDispatcher, + execution_mode: VmExecutionMode, + with_refund_tracer: bool, + custom_pubdata_tracer: Option>, + ) -> (VmExecutionStopReason, VmExecutionResultAndLogs) { + let refund_tracers = + with_refund_tracer.then_some(RefundsTracer::new(self.batch_env.clone())); + let mut tx_tracer: DefaultExecutionTracer = DefaultExecutionTracer::new( + self.system_env.default_validation_computational_gas_limit, + execution_mode, + dispatcher, + self.storage.clone(), + refund_tracers, + custom_pubdata_tracer + .or_else(|| Some(PubdataTracer::new(self.batch_env.clone(), execution_mode))), + ); + + let timestamp_initial = Timestamp(self.state.local_state.timestamp); + let cycles_initial = self.state.local_state.monotonic_cycle_counter; + let gas_remaining_before = self.gas_remaining(); + let spent_pubdata_counter_before = self.state.local_state.spent_pubdata_counter; + + let stop_reason = self.execute_with_default_tracer(&mut tx_tracer); + + let gas_remaining_after = self.gas_remaining(); + + let logs = self.collect_execution_logs_after_timestamp(timestamp_initial); + + let (refunds, pubdata_published) = tx_tracer + .refund_tracer + .as_ref() + .map(|x| (x.get_refunds(), x.pubdata_published())) + .unwrap_or_default(); + + let statistics = self.get_statistics( + timestamp_initial, + cycles_initial, + &tx_tracer, + gas_remaining_before, + gas_remaining_after, + spent_pubdata_counter_before, + pubdata_published, + logs.total_log_queries_count, + circuit_statistic_from_cycles(tx_tracer.circuits_tracer.statistics), + ); + let result = tx_tracer.result_tracer.into_result(); + + let result = VmExecutionResultAndLogs { + result, + logs, + statistics, + refunds, + }; + + (stop_reason, result) + } + + /// Execute vm with given tracers until the stop reason is reached. + fn execute_with_default_tracer( + &mut self, + tracer: &mut DefaultExecutionTracer, + ) -> VmExecutionStopReason { + tracer.initialize_tracer(&mut self.state); + let result = loop { + // Sanity check: we should never reach the maximum value, because then we won't be able to process the next cycle. + assert_ne!( + self.state.local_state.monotonic_cycle_counter, + u32::MAX, + "VM reached maximum possible amount of cycles. Vm state: {:?}", + self.state + ); + + self.state + .cycle(tracer) + .expect("Failed execution VM cycle."); + + if let TracerExecutionStatus::Stop(reason) = + tracer.finish_cycle(&mut self.state, &mut self.bootloader_state) + { + break VmExecutionStopReason::TracerRequestedStop(reason); + } + if self.has_ended() { + break VmExecutionStopReason::VmFinished; + } + }; + tracer.after_vm_execution(&mut self.state, &self.bootloader_state, result.clone()); + result + } + + fn has_ended(&self) -> bool { + match vm_may_have_ended_inner(&self.state) { + None | Some(VmExecutionResult::MostLikelyDidNotFinish(_, _)) => false, + Some( + VmExecutionResult::Ok(_) | VmExecutionResult::Revert(_) | VmExecutionResult::Panic, + ) => true, + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/gas.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/gas.rs new file mode 100644 index 000000000000..2ac365f4a38e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/gas.rs @@ -0,0 +1,32 @@ +use zksync_state::WriteStorage; + +use crate::{ + interface::VmInterface, + vm_1_4_1::{tracers::DefaultExecutionTracer, vm::Vm}, + HistoryMode, +}; + +impl Vm { + pub(crate) fn calculate_computational_gas_used( + &self, + tracer: &DefaultExecutionTracer, + gas_remaining_before: u32, + spent_pubdata_counter_before: u32, + ) -> u32 { + let total_gas_used = gas_remaining_before + .checked_sub(self.gas_remaining()) + .expect("underflow"); + let gas_used_on_pubdata = + tracer.gas_spent_on_pubdata(&self.state.local_state) - spent_pubdata_counter_before; + total_gas_used + .checked_sub(gas_used_on_pubdata) + .unwrap_or_else(|| { + tracing::error!( + "Gas used on pubdata is greater than total gas used. On pubdata: {}, total: {}", + gas_used_on_pubdata, + total_gas_used + ); + 0 + }) + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/logs.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/logs.rs new file mode 100644 index 000000000000..c35dfd666f21 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/logs.rs @@ -0,0 +1,76 @@ +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_types::{ + event::extract_l2tol1logs_from_l1_messenger, + l2_to_l1_log::{L2ToL1Log, SystemL2ToL1Log, UserL2ToL1Log}, + VmEvent, +}; + +use crate::{ + glue::GlueInto, + interface::types::outputs::VmExecutionLogs, + vm_1_4_1::{old_vm::utils::precompile_calls_count_after_timestamp, utils::logs, vm::Vm}, + HistoryMode, +}; + +impl Vm { + pub(crate) fn collect_execution_logs_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> VmExecutionLogs { + let storage_logs: Vec<_> = self + .state + .storage + .storage_log_queries_after_timestamp(from_timestamp) + .iter() + .map(|log| **log) + .collect(); + let storage_logs_count = storage_logs.len(); + + let (events, system_l2_to_l1_logs) = + self.collect_events_and_l1_system_logs_after_timestamp(from_timestamp); + + let log_queries = self + .state + .event_sink + .log_queries_after_timestamp(from_timestamp); + + let precompile_calls_count = precompile_calls_count_after_timestamp( + self.state.precompiles_processor.timestamp_history.inner(), + from_timestamp, + ); + + let user_logs = extract_l2tol1logs_from_l1_messenger(&events); + + let total_log_queries_count = + storage_logs_count + log_queries.len() + precompile_calls_count; + + VmExecutionLogs { + storage_logs: storage_logs + .into_iter() + .map(|log| log.glue_into()) + .collect(), + events, + user_l2_to_l1_logs: user_logs + .into_iter() + .map(|log| UserL2ToL1Log(log.into())) + .collect(), + system_l2_to_l1_logs: system_l2_to_l1_logs + .into_iter() + .map(SystemL2ToL1Log) + .collect(), + total_log_queries_count, + } + } + + pub(crate) fn collect_events_and_l1_system_logs_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> (Vec, Vec) { + logs::collect_events_and_l1_system_logs_after_timestamp( + &self.state, + &self.batch_env, + from_timestamp.glue_into(), + ) + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/mod.rs new file mode 100644 index 000000000000..161732cf0348 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/mod.rs @@ -0,0 +1,7 @@ +mod bytecode; +mod execution; +mod gas; +mod logs; +mod snapshots; +mod statistics; +mod tx; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs new file mode 100644 index 000000000000..2682b6183c52 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs @@ -0,0 +1,91 @@ +use std::time::Duration; + +use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics}; +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_state::WriteStorage; + +use crate::vm_1_4_1::{ + old_vm::{history_recorder::HistoryEnabled, oracles::OracleWithHistory}, + types::internals::VmSnapshot, + vm::Vm, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet, EncodeLabelValue)] +#[metrics(label = "stage", rename_all = "snake_case")] +enum RollbackStage { + DecommitmentProcessorRollback, + EventSinkRollback, + StorageRollback, + MemoryRollback, + PrecompilesProcessorRollback, + ApplyBootloaderSnapshot, +} + +#[derive(Debug, Metrics)] +#[metrics(prefix = "server_vm")] +struct VmMetrics { + #[metrics(buckets = Buckets::LATENCIES)] + rollback_time: Family>, +} + +#[vise::register] +static METRICS: vise::Global = vise::Global::new(); + +/// Implementation of VM related to rollbacks inside virtual machine +impl Vm { + pub(crate) fn make_snapshot_inner(&mut self) { + self.snapshots.push(VmSnapshot { + // Vm local state contains O(1) various parameters (registers/etc). + // The only "expensive" copying here is copying of the call stack. + // It will take `O(callstack_depth)` to copy it. + // So it is generally recommended to get snapshots of the bootloader frame, + // where the depth is 1. + local_state: self.state.local_state.clone(), + bootloader_state: self.bootloader_state.get_snapshot(), + }); + } + + pub(crate) fn rollback_to_snapshot(&mut self, snapshot: VmSnapshot) { + let VmSnapshot { + local_state, + bootloader_state, + } = snapshot; + + let stage_latency = + METRICS.rollback_time[&RollbackStage::DecommitmentProcessorRollback].start(); + let timestamp = Timestamp(local_state.timestamp); + tracing::trace!("Rolling back decomitter"); + self.state + .decommittment_processor + .rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = METRICS.rollback_time[&RollbackStage::EventSinkRollback].start(); + tracing::trace!("Rolling back event_sink"); + self.state.event_sink.rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = METRICS.rollback_time[&RollbackStage::StorageRollback].start(); + tracing::trace!("Rolling back storage"); + self.state.storage.rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = METRICS.rollback_time[&RollbackStage::MemoryRollback].start(); + tracing::trace!("Rolling back memory"); + self.state.memory.rollback_to_timestamp(timestamp); + stage_latency.observe(); + + let stage_latency = + METRICS.rollback_time[&RollbackStage::PrecompilesProcessorRollback].start(); + tracing::trace!("Rolling back precompiles_processor"); + self.state + .precompiles_processor + .rollback_to_timestamp(timestamp); + stage_latency.observe(); + + self.state.local_state = local_state; + let stage_latency = METRICS.rollback_time[&RollbackStage::ApplyBootloaderSnapshot].start(); + self.bootloader_state.apply_snapshot(bootloader_state); + stage_latency.observe(); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/statistics.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/statistics.rs new file mode 100644 index 000000000000..dea1b3d29251 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/statistics.rs @@ -0,0 +1,73 @@ +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_types::{circuit::CircuitStatistic, U256}; + +use crate::{ + interface::{VmExecutionStatistics, VmMemoryMetrics}, + vm_1_4_1::{tracers::DefaultExecutionTracer, vm::Vm}, + HistoryMode, +}; + +/// Module responsible for observing the VM behavior, i.e. calculating the statistics of the VM runs +/// or reporting the VM memory usage. + +impl Vm { + /// Get statistics about TX execution. + #[allow(clippy::too_many_arguments)] + pub(crate) fn get_statistics( + &self, + timestamp_initial: Timestamp, + cycles_initial: u32, + tracer: &DefaultExecutionTracer, + gas_remaining_before: u32, + gas_remaining_after: u32, + spent_pubdata_counter_before: u32, + pubdata_published: u32, + total_log_queries_count: usize, + circuit_statistic: CircuitStatistic, + ) -> VmExecutionStatistics { + let computational_gas_used = self.calculate_computational_gas_used( + tracer, + gas_remaining_before, + spent_pubdata_counter_before, + ); + VmExecutionStatistics { + contracts_used: self + .state + .decommittment_processor + .get_decommitted_bytecodes_after_timestamp(timestamp_initial), + cycles_used: self.state.local_state.monotonic_cycle_counter - cycles_initial, + gas_used: gas_remaining_before - gas_remaining_after, + gas_remaining: gas_remaining_after, + computational_gas_used, + total_log_queries: total_log_queries_count, + pubdata_published, + circuit_statistic, + } + } + + /// Returns the hashes the bytecodes that have been decommitted by the decommitment processor. + pub(crate) fn get_used_contracts(&self) -> Vec { + self.state + .decommittment_processor + .decommitted_code_hashes + .inner() + .keys() + .cloned() + .collect() + } + + /// Returns the info about all oracles' sizes. + pub(crate) fn record_vm_memory_metrics_inner(&self) -> VmMemoryMetrics { + VmMemoryMetrics { + event_sink_inner: self.state.event_sink.get_size(), + event_sink_history: self.state.event_sink.get_history_size(), + memory_inner: self.state.memory.get_size(), + memory_history: self.state.memory.get_history_size(), + decommittment_processor_inner: self.state.decommittment_processor.get_size(), + decommittment_processor_history: self.state.decommittment_processor.get_history_size(), + storage_inner: self.state.storage.get_size(), + storage_history: self.state.storage.get_history_size(), + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/tx.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/tx.rs new file mode 100644 index 000000000000..4aea2649c99c --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/tx.rs @@ -0,0 +1,66 @@ +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_types::{l1::is_l1_tx_type, Transaction}; + +use crate::{ + vm_1_4_1::{ + constants::BOOTLOADER_HEAP_PAGE, + implementation::bytecode::{bytecode_to_factory_dep, compress_bytecodes}, + types::internals::TransactionData, + vm::Vm, + }, + HistoryMode, +}; + +impl Vm { + pub(crate) fn push_raw_transaction( + &mut self, + tx: TransactionData, + predefined_overhead: u32, + predefined_refund: u32, + with_compression: bool, + ) { + let timestamp = Timestamp(self.state.local_state.timestamp); + let codes_for_decommiter = tx + .factory_deps + .iter() + .map(|dep| bytecode_to_factory_dep(dep.clone())) + .collect(); + + let compressed_bytecodes = if is_l1_tx_type(tx.tx_type) || !with_compression { + // L1 transactions do not need compression + vec![] + } else { + compress_bytecodes(&tx.factory_deps, self.state.storage.storage.get_ptr()) + }; + + self.state + .decommittment_processor + .populate(codes_for_decommiter, timestamp); + + let trusted_ergs_limit = tx.trusted_ergs_limit(); + + let memory = self.bootloader_state.push_tx( + tx, + predefined_overhead, + predefined_refund, + compressed_bytecodes, + trusted_ergs_limit, + self.system_env.chain_id, + ); + + self.state + .memory + .populate_page(BOOTLOADER_HEAP_PAGE as usize, memory, timestamp); + } + + pub(crate) fn push_transaction_with_compression( + &mut self, + tx: Transaction, + with_compression: bool, + ) { + let tx: TransactionData = tx.into(); + let overhead = tx.overhead_gas(); + self.push_raw_transaction(tx, overhead, 0, with_compression); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/mod.rs new file mode 100644 index 000000000000..c3df28f6c31c --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/mod.rs @@ -0,0 +1,36 @@ +pub use self::{ + bootloader_state::BootloaderState, + old_vm::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HistoryDisabled, HistoryEnabled, HistoryMode, + }, + memory::SimpleMemory, + }, + oracles::storage::StorageOracle, + tracers::{ + dispatcher::TracerDispatcher, + traits::{ToTracerPointer, TracerPointer, VmTracer}, + }, + types::internals::ZkSyncVmState, + utils::transaction_encoding::TransactionVmExt, + vm::Vm, +}; +pub use crate::interface::types::{ + inputs::{L1BatchEnv, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode}, + outputs::{ + BootloaderMemory, CurrentExecutionState, ExecutionResult, FinishedL1Batch, L2Block, + Refunds, VmExecutionLogs, VmExecutionResultAndLogs, VmExecutionStatistics, VmMemoryMetrics, + }, +}; + +mod bootloader_state; +pub mod constants; +mod implementation; +mod old_vm; +mod oracles; +#[cfg(test)] +mod tests; +pub(crate) mod tracers; +mod types; +pub mod utils; +mod vm; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/event_sink.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/event_sink.rs new file mode 100644 index 000000000000..5886ea067760 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/event_sink.rs @@ -0,0 +1,263 @@ +use std::collections::HashMap; + +use itertools::Itertools; +use zk_evm_1_4_1::{ + abstractions::EventSink, + aux_structures::{LogQuery, Timestamp}, + reference_impls::event_sink::EventMessage, + zkevm_opcode_defs::system_params::{ + BOOTLOADER_FORMAL_ADDRESS, EVENT_AUX_BYTE, L1_MESSAGE_AUX_BYTE, + }, +}; +use zksync_types::U256; + +use crate::vm_1_4_1::old_vm::{ + history_recorder::{AppDataFrameManagerWithHistory, HistoryEnabled, HistoryMode}, + oracles::OracleWithHistory, +}; + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct InMemoryEventSink { + frames_stack: AppDataFrameManagerWithHistory, H>, +} + +impl OracleWithHistory for InMemoryEventSink { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.frames_stack.rollback_to_timestamp(timestamp); + } +} + +// as usual, if we rollback the current frame then we apply changes to storage immediately, +// otherwise we carry rollbacks to the parent's frames + +impl InMemoryEventSink { + pub fn flatten(&self) -> (Vec, Vec, Vec) { + assert_eq!( + self.frames_stack.len(), + 1, + "there must exist an initial keeper frame" + ); + // we forget rollbacks as we have finished the execution and can just apply them + let history = self.frames_stack.forward().current_frame(); + + let (events, l1_messages) = Self::events_and_l1_messages_from_history(history); + let events_logs = Self::events_logs_from_history(history); + + (events_logs, events, l1_messages) + } + + pub fn get_log_queries(&self) -> usize { + self.frames_stack.forward().current_frame().len() + } + + /// Returns the log queries in the current frame where `log_query.timestamp >= from_timestamp`. + pub fn log_queries_after_timestamp(&self, from_timestamp: Timestamp) -> &[Box] { + let events = self.frames_stack.forward().current_frame(); + + // Select all of the last elements where `e.timestamp >= from_timestamp`. + // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. + events + .rsplit(|e| e.timestamp < from_timestamp) + .next() + .unwrap_or(&[]) + } + + pub fn get_events_and_l2_l1_logs_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> (Vec, Vec) { + Self::events_and_l1_messages_from_history(self.log_queries_after_timestamp(from_timestamp)) + } + + fn events_logs_from_history(history: &[Box]) -> Vec { + // Filter out all the L2->L1 logs and leave only events + let mut events = history + .iter() + .filter_map(|log_query| (log_query.aux_byte == EVENT_AUX_BYTE).then_some(**log_query)) + .collect_vec(); + + // Sort the events by timestamp and rollback flag, basically ensuring that + // if an event has been rolled back, the original event and its rollback will be put together + events.sort_by_key(|log| (log.timestamp, log.rollback)); + + let mut stack = Vec::::new(); + let mut net_history = vec![]; + for el in events.iter() { + assert_eq!(el.shard_id, 0, "only rollup shard is supported"); + if stack.is_empty() { + assert!(!el.rollback); + stack.push(*el); + } else { + // we can always pop as it's either one to add to queue, or discard + let previous = stack.pop().unwrap(); + if previous.timestamp == el.timestamp { + // Only rollback can have the same timestamp, so here we do nothing and simply + // double check the invariants + assert!(!previous.rollback); + assert!(el.rollback); + assert!(previous.rw_flag); + assert!(el.rw_flag); + assert_eq!(previous.tx_number_in_block, el.tx_number_in_block); + assert_eq!(previous.shard_id, el.shard_id); + assert_eq!(previous.address, el.address); + assert_eq!(previous.key, el.key); + assert_eq!(previous.written_value, el.written_value); + assert_eq!(previous.is_service, el.is_service); + continue; + } else { + // The event on the stack has not been rolled back. It must be a different event, + // with a different timestamp. + assert!(!el.rollback); + stack.push(*el); + + // cleanup some fields + // flags are conventions + let sorted_log_query = LogQuery { + timestamp: Timestamp(0), + tx_number_in_block: previous.tx_number_in_block, + aux_byte: 0, + shard_id: previous.shard_id, + address: previous.address, + key: previous.key, + read_value: U256::zero(), + written_value: previous.written_value, + rw_flag: false, + rollback: false, + is_service: previous.is_service, + }; + + net_history.push(sorted_log_query); + } + } + } + + // In case the stack is non-empty, then the last element of it has not been rolled back. + if let Some(previous) = stack.pop() { + // cleanup some fields + // flags are conventions + let sorted_log_query = LogQuery { + timestamp: Timestamp(0), + tx_number_in_block: previous.tx_number_in_block, + aux_byte: 0, + shard_id: previous.shard_id, + address: previous.address, + key: previous.key, + read_value: U256::zero(), + written_value: previous.written_value, + rw_flag: false, + rollback: false, + is_service: previous.is_service, + }; + + net_history.push(sorted_log_query); + } + + net_history + } + + fn events_and_l1_messages_from_history( + history: &[Box], + ) -> (Vec, Vec) { + let mut tmp = HashMap::::with_capacity(history.len()); + + // note that we only use "forward" part and discard the rollbacks at the end, + // since if rollbacks of parents were not appended anywhere we just still keep them + for el in history { + // we are time ordered here in terms of rollbacks + if tmp.get(&el.timestamp.0).is_some() { + assert!(el.rollback); + tmp.remove(&el.timestamp.0); + } else { + assert!(!el.rollback); + tmp.insert(el.timestamp.0, **el); + } + } + + // naturally sorted by timestamp + let mut keys: Vec<_> = tmp.keys().cloned().collect(); + keys.sort_unstable(); + + let mut events = vec![]; + let mut l1_messages = vec![]; + + for k in keys.into_iter() { + let el = tmp.remove(&k).unwrap(); + let LogQuery { + shard_id, + is_service, + tx_number_in_block, + address, + key, + written_value, + aux_byte, + .. + } = el; + + let event = EventMessage { + shard_id, + is_first: is_service, + tx_number_in_block, + address, + key, + value: written_value, + }; + + if aux_byte == EVENT_AUX_BYTE { + events.push(event); + } else { + l1_messages.push(event); + } + } + + (events, l1_messages) + } + + pub(crate) fn get_size(&self) -> usize { + self.frames_stack.get_size() + } + + pub fn get_history_size(&self) -> usize { + self.frames_stack.get_history_size() + } + + pub fn delete_history(&mut self) { + self.frames_stack.delete_history(); + } +} + +impl EventSink for InMemoryEventSink { + // when we enter a new frame we should remember all our current applications and rollbacks + // when we exit the current frame then if we did panic we should concatenate all current + // forward and rollback cases + + fn add_partial_query(&mut self, _monotonic_cycle_counter: u32, mut query: LogQuery) { + assert!(query.rw_flag); + assert!(query.aux_byte == EVENT_AUX_BYTE || query.aux_byte == L1_MESSAGE_AUX_BYTE); + assert!(!query.rollback); + + // just append to rollbacks and a full history + + self.frames_stack + .push_forward(Box::new(query), query.timestamp); + // we do not need it explicitly here, but let's be consistent with circuit counterpart + query.rollback = true; + self.frames_stack + .push_rollback(Box::new(query), query.timestamp); + } + + fn start_frame(&mut self, timestamp: Timestamp) { + self.frames_stack.push_frame(timestamp) + } + + fn finish_frame(&mut self, panicked: bool, timestamp: Timestamp) { + // if we panic then we append forward and rollbacks to the forward of parent, + // otherwise we place rollbacks of child before rollbacks of the parent + if panicked { + self.frames_stack.move_rollback_to_forward( + |q| q.address != *BOOTLOADER_FORMAL_ADDRESS || q.aux_byte != EVENT_AUX_BYTE, + timestamp, + ); + } + self.frames_stack.merge_frame(timestamp); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/events.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/events.rs new file mode 100644 index 000000000000..fc97b6f4a419 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/events.rs @@ -0,0 +1,146 @@ +use zk_evm_1_4_1::{ethereum_types::Address, reference_impls::event_sink::EventMessage}; +use zksync_types::{L1BatchNumber, VmEvent, EVENT_WRITER_ADDRESS, H256}; +use zksync_utils::{be_chunks_to_h256_words, h256_to_account_address}; + +#[derive(Clone)] +pub(crate) struct SolidityLikeEvent { + pub(crate) shard_id: u8, + pub(crate) tx_number_in_block: u16, + pub(crate) address: Address, + pub(crate) topics: Vec<[u8; 32]>, + pub(crate) data: Vec, +} + +impl SolidityLikeEvent { + pub(crate) fn into_vm_event(self, block_number: L1BatchNumber) -> VmEvent { + VmEvent { + location: (block_number, self.tx_number_in_block as u32), + address: self.address, + indexed_topics: be_chunks_to_h256_words(self.topics), + value: self.data, + } + } +} + +fn merge_events_inner(events: Vec) -> Vec { + let mut result = vec![]; + let mut current: Option<(usize, u32, SolidityLikeEvent)> = None; + + for message in events.into_iter() { + if !message.is_first { + let EventMessage { + shard_id, + is_first: _, + tx_number_in_block, + address, + key, + value, + } = message; + + if let Some((mut remaining_data_length, mut remaining_topics, mut event)) = + current.take() + { + if event.address != address + || event.shard_id != shard_id + || event.tx_number_in_block != tx_number_in_block + { + continue; + } + let mut data_0 = [0u8; 32]; + let mut data_1 = [0u8; 32]; + key.to_big_endian(&mut data_0); + value.to_big_endian(&mut data_1); + for el in [data_0, data_1].iter() { + if remaining_topics != 0 { + event.topics.push(*el); + remaining_topics -= 1; + } else if remaining_data_length != 0 { + if remaining_data_length >= 32 { + event.data.extend_from_slice(el); + remaining_data_length -= 32; + } else { + event.data.extend_from_slice(&el[..remaining_data_length]); + remaining_data_length = 0; + } + } + } + + if remaining_data_length != 0 || remaining_topics != 0 { + current = Some((remaining_data_length, remaining_topics, event)) + } else { + result.push(event); + } + } + } else { + // start new one. First take the old one only if it's well formed + if let Some((remaining_data_length, remaining_topics, event)) = current.take() { + if remaining_data_length == 0 && remaining_topics == 0 { + result.push(event); + } + } + + let EventMessage { + shard_id, + is_first: _, + tx_number_in_block, + address, + key, + value, + } = message; + // split key as our internal marker. Ignore higher bits + let mut num_topics = key.0[0] as u32; + let mut data_length = (key.0[0] >> 32) as usize; + let mut buffer = [0u8; 32]; + value.to_big_endian(&mut buffer); + + let (topics, data) = if num_topics == 0 && data_length == 0 { + (vec![], vec![]) + } else if num_topics == 0 { + data_length -= 32; + (vec![], buffer.to_vec()) + } else { + num_topics -= 1; + (vec![buffer], vec![]) + }; + + let new_event = SolidityLikeEvent { + shard_id, + tx_number_in_block, + address, + topics, + data, + }; + + current = Some((data_length, num_topics, new_event)) + } + } + + // add the last one + if let Some((remaining_data_length, remaining_topics, event)) = current.take() { + if remaining_data_length == 0 && remaining_topics == 0 { + result.push(event); + } + } + + result +} + +pub(crate) fn merge_events(events: Vec) -> Vec { + let raw_events = merge_events_inner(events); + + raw_events + .into_iter() + .filter(|e| e.address == EVENT_WRITER_ADDRESS) + .map(|event| { + // The events writer events where the first topic is the actual address of the event and the rest of the topics are real topics + let address = h256_to_account_address(&H256(event.topics[0])); + let topics = event.topics.into_iter().skip(1).collect(); + + SolidityLikeEvent { + topics, + address, + ..event + } + }) + .collect() +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/history_recorder.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/history_recorder.rs new file mode 100644 index 000000000000..7a0b3f45edf3 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/history_recorder.rs @@ -0,0 +1,811 @@ +use std::{collections::HashMap, fmt::Debug, hash::Hash}; + +use zk_evm_1_4_1::{ + aux_structures::Timestamp, + vm_state::PrimitiveValue, + zkevm_opcode_defs::{self}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{StorageKey, U256}; +use zksync_utils::{h256_to_u256, u256_to_h256}; + +pub(crate) type MemoryWithHistory = HistoryRecorder; +pub(crate) type IntFrameManagerWithHistory = HistoryRecorder, H>; + +// Within the same cycle, timestamps in range `timestamp..timestamp+TIME_DELTA_PER_CYCLE-1` +// can be used. This can sometimes violate monotonicity of the timestamp within the +// same cycle, so it should be normalized. +#[inline] +fn normalize_timestamp(timestamp: Timestamp) -> Timestamp { + let timestamp = timestamp.0; + + // Making sure it is divisible by `TIME_DELTA_PER_CYCLE` + Timestamp(timestamp - timestamp % zkevm_opcode_defs::TIME_DELTA_PER_CYCLE) +} + +/// Accepts history item as its parameter and applies it. +pub trait WithHistory { + type HistoryRecord; + type ReturnValue; + + // Applies an action and returns the action that would + // rollback its effect as well as some returned value + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue); +} + +type EventList = Vec<(Timestamp, ::HistoryRecord)>; + +/// Controls if rolling back is possible or not. +/// Either [HistoryEnabled] or [HistoryDisabled]. +pub trait HistoryMode: private::Sealed + Debug + Clone + Default { + type History: Default; + + fn clone_history(history: &Self::History) -> Self::History + where + T::HistoryRecord: Clone; + fn mutate_history)>( + recorder: &mut HistoryRecorder, + f: F, + ); + fn borrow_history) -> R, R>( + recorder: &HistoryRecorder, + f: F, + default: R, + ) -> R; +} + +mod private { + pub trait Sealed {} + impl Sealed for super::HistoryEnabled {} + impl Sealed for super::HistoryDisabled {} +} + +// derives require that all type parameters implement the trait, which is why +// HistoryEnabled/Disabled derive so many traits even though they mostly don't +// exist at runtime. + +/// A data structure with this parameter can be rolled back. +/// See also: [HistoryDisabled] +#[derive(Debug, Clone, Default, PartialEq)] +pub struct HistoryEnabled; + +/// A data structure with this parameter cannot be rolled back. +/// It won't even have rollback methods. +/// See also: [HistoryEnabled] +#[derive(Debug, Clone, Default)] +pub struct HistoryDisabled; + +impl HistoryMode for HistoryEnabled { + type History = EventList; + + fn clone_history(history: &Self::History) -> Self::History + where + T::HistoryRecord: Clone, + { + history.clone() + } + fn mutate_history)>( + recorder: &mut HistoryRecorder, + f: F, + ) { + f(&mut recorder.inner, &mut recorder.history) + } + fn borrow_history) -> R, R>( + recorder: &HistoryRecorder, + f: F, + _: R, + ) -> R { + f(&recorder.history) + } +} + +impl HistoryMode for HistoryDisabled { + type History = (); + + fn clone_history(_: &Self::History) -> Self::History {} + fn mutate_history)>( + _: &mut HistoryRecorder, + _: F, + ) { + } + fn borrow_history) -> R, R>( + _: &HistoryRecorder, + _: F, + default: R, + ) -> R { + default + } +} + +/// A struct responsible for tracking history for +/// a component that is passed as a generic parameter to it (`inner`). +#[derive(Default)] +pub struct HistoryRecorder { + inner: T, + history: H::History, +} + +impl PartialEq for HistoryRecorder +where + T::HistoryRecord: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + && self.borrow_history(|h1| other.borrow_history(|h2| h1 == h2, true), true) + } +} + +impl Debug for HistoryRecorder +where + T::HistoryRecord: Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug_struct = f.debug_struct("HistoryRecorder"); + debug_struct.field("inner", &self.inner); + self.borrow_history( + |h| { + debug_struct.field("history", h); + }, + (), + ); + debug_struct.finish() + } +} + +impl Clone for HistoryRecorder +where + T::HistoryRecord: Clone, + H: HistoryMode, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + history: H::clone_history(&self.history), + } + } +} + +impl HistoryRecorder { + pub fn from_inner(inner: T) -> Self { + Self { + inner, + history: Default::default(), + } + } + + pub fn inner(&self) -> &T { + &self.inner + } + + /// If history exists, modify it using `f`. + pub fn mutate_history)>(&mut self, f: F) { + H::mutate_history(self, f); + } + + /// If history exists, feed it into `f`. Otherwise return `default`. + pub fn borrow_history) -> R, R>(&self, f: F, default: R) -> R { + H::borrow_history(self, f, default) + } + + pub fn apply_historic_record( + &mut self, + item: T::HistoryRecord, + timestamp: Timestamp, + ) -> T::ReturnValue { + let (reversed_item, return_value) = self.inner.apply_historic_record(item); + + self.mutate_history(|_, history| { + let last_recorded_timestamp = history.last().map(|(t, _)| *t).unwrap_or(Timestamp(0)); + let timestamp = normalize_timestamp(timestamp); + assert!( + last_recorded_timestamp <= timestamp, + "Timestamps are not monotonic" + ); + history.push((timestamp, reversed_item)); + }); + + return_value + } + + /// Deletes all the history for its component, making + /// its current state irreversible + pub fn delete_history(&mut self) { + self.mutate_history(|_, h| h.clear()) + } +} + +impl HistoryRecorder { + pub fn history(&self) -> &Vec<(Timestamp, T::HistoryRecord)> { + &self.history + } + + pub(crate) fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + loop { + let should_undo = self + .history + .last() + .map(|(item_timestamp, _)| *item_timestamp >= timestamp) + .unwrap_or(false); + if !should_undo { + break; + } + + let (_, item_to_apply) = self.history.pop().unwrap(); + self.inner.apply_historic_record(item_to_apply); + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum VectorHistoryEvent { + Push(X), + Pop, +} + +impl WithHistory for Vec { + type HistoryRecord = VectorHistoryEvent; + type ReturnValue = Option; + fn apply_historic_record( + &mut self, + item: VectorHistoryEvent, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + match item { + VectorHistoryEvent::Pop => { + // Note, that here we assume that the users + // will check themselves whether this vector is empty + // prior to popping from it. + let poped_item = self.pop().unwrap(); + + (VectorHistoryEvent::Push(poped_item), Some(poped_item)) + } + VectorHistoryEvent::Push(x) => { + self.push(x); + + (VectorHistoryEvent::Pop, None) + } + } + } +} + +impl HistoryRecorder, H> { + pub fn push(&mut self, elem: T, timestamp: Timestamp) { + self.apply_historic_record(VectorHistoryEvent::Push(elem), timestamp); + } + + pub fn pop(&mut self, timestamp: Timestamp) -> T { + self.apply_historic_record(VectorHistoryEvent::Pop, timestamp) + .unwrap() + } + + pub fn len(&self) -> usize { + self.inner.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct HashMapHistoryEvent { + pub key: K, + pub value: Option, +} + +impl WithHistory for HashMap { + type HistoryRecord = HashMapHistoryEvent; + type ReturnValue = Option; + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + let HashMapHistoryEvent { key, value } = item; + + let prev_value = match value { + Some(x) => self.insert(key, x), + None => self.remove(&key), + }; + + ( + HashMapHistoryEvent { + key, + value: prev_value.clone(), + }, + prev_value, + ) + } +} + +impl HistoryRecorder, H> { + pub fn insert(&mut self, key: K, value: V, timestamp: Timestamp) -> Option { + self.apply_historic_record( + HashMapHistoryEvent { + key, + value: Some(value), + }, + timestamp, + ) + } + + pub(crate) fn remove(&mut self, key: K, timestamp: Timestamp) -> Option { + self.apply_historic_record(HashMapHistoryEvent { key, value: None }, timestamp) + } +} + +/// A stack of stacks. The inner stacks are called frames. +/// +/// Does not support popping from the outer stack. Instead, the outer stack can +/// push its topmost frame's contents onto the previous frame. +#[derive(Debug, Clone, PartialEq)] +pub struct FramedStack { + data: Vec, + frame_start_indices: Vec, +} + +impl Default for FramedStack { + fn default() -> Self { + // We typically require at least the first frame to be there + // since the last user-provided frame might be reverted + Self { + data: vec![], + frame_start_indices: vec![0], + } + } +} + +#[derive(Debug, Clone, PartialEq)] +pub enum FramedStackEvent { + Push(T), + Pop, + PushFrame(usize), + MergeFrame, +} + +impl WithHistory for FramedStack { + type HistoryRecord = FramedStackEvent; + type ReturnValue = (); + + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + use FramedStackEvent::*; + match item { + Push(x) => { + self.data.push(x); + (Pop, ()) + } + Pop => { + let x = self.data.pop().unwrap(); + (Push(x), ()) + } + PushFrame(i) => { + self.frame_start_indices.push(i); + (MergeFrame, ()) + } + MergeFrame => { + let pos = self.frame_start_indices.pop().unwrap(); + (PushFrame(pos), ()) + } + } + } +} + +impl FramedStack { + fn push_frame(&self) -> FramedStackEvent { + FramedStackEvent::PushFrame(self.data.len()) + } + + pub fn current_frame(&self) -> &[T] { + &self.data[*self.frame_start_indices.last().unwrap()..self.data.len()] + } + + fn len(&self) -> usize { + self.frame_start_indices.len() + } + + /// Returns the amount of memory taken up by the stored items + pub fn get_size(&self) -> usize { + self.data.len() * std::mem::size_of::() + } +} + +impl HistoryRecorder, H> { + pub fn push_to_frame(&mut self, x: T, timestamp: Timestamp) { + self.apply_historic_record(FramedStackEvent::Push(x), timestamp); + } + pub fn clear_frame(&mut self, timestamp: Timestamp) { + let start = *self.inner.frame_start_indices.last().unwrap(); + while self.inner.data.len() > start { + self.apply_historic_record(FramedStackEvent::Pop, timestamp); + } + } + pub fn extend_frame(&mut self, items: impl IntoIterator, timestamp: Timestamp) { + for x in items { + self.push_to_frame(x, timestamp); + } + } + pub fn push_frame(&mut self, timestamp: Timestamp) { + self.apply_historic_record(self.inner.push_frame(), timestamp); + } + pub fn merge_frame(&mut self, timestamp: Timestamp) { + self.apply_historic_record(FramedStackEvent::MergeFrame, timestamp); + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct AppDataFrameManagerWithHistory { + forward: HistoryRecorder, H>, + rollback: HistoryRecorder, H>, +} + +impl Default for AppDataFrameManagerWithHistory { + fn default() -> Self { + Self { + forward: Default::default(), + rollback: Default::default(), + } + } +} + +impl AppDataFrameManagerWithHistory { + pub(crate) fn delete_history(&mut self) { + self.forward.delete_history(); + self.rollback.delete_history(); + } + + pub(crate) fn push_forward(&mut self, item: T, timestamp: Timestamp) { + self.forward.push_to_frame(item, timestamp); + } + pub(crate) fn push_rollback(&mut self, item: T, timestamp: Timestamp) { + self.rollback.push_to_frame(item, timestamp); + } + pub(crate) fn push_frame(&mut self, timestamp: Timestamp) { + self.forward.push_frame(timestamp); + self.rollback.push_frame(timestamp); + } + pub(crate) fn merge_frame(&mut self, timestamp: Timestamp) { + self.forward.merge_frame(timestamp); + self.rollback.merge_frame(timestamp); + } + + pub(crate) fn len(&self) -> usize { + self.forward.inner.len() + } + pub(crate) fn forward(&self) -> &FramedStack { + &self.forward.inner + } + pub(crate) fn rollback(&self) -> &FramedStack { + &self.rollback.inner + } + + /// Returns the amount of memory taken up by the stored items + pub(crate) fn get_size(&self) -> usize { + self.forward().get_size() + self.rollback().get_size() + } + + pub(crate) fn get_history_size(&self) -> usize { + (self.forward.borrow_history(|h| h.len(), 0) + self.rollback.borrow_history(|h| h.len(), 0)) + * std::mem::size_of::< as WithHistory>::HistoryRecord>() + } +} + +impl AppDataFrameManagerWithHistory { + pub(crate) fn move_rollback_to_forward bool>( + &mut self, + filter: F, + timestamp: Timestamp, + ) { + for x in self.rollback.inner.current_frame().iter().rev() { + if filter(x) { + self.forward.push_to_frame(x.clone(), timestamp); + } + } + self.rollback.clear_frame(timestamp); + } +} + +impl AppDataFrameManagerWithHistory { + pub(crate) fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.forward.rollback_to_timestamp(timestamp); + self.rollback.rollback_to_timestamp(timestamp); + } +} + +const PRIMITIVE_VALUE_EMPTY: PrimitiveValue = PrimitiveValue::empty(); +const PAGE_SUBDIVISION_LEN: usize = 64; + +#[derive(Debug, Default, Clone)] +struct MemoryPage { + root: Vec>>, +} + +impl MemoryPage { + fn get(&self, slot: usize) -> &PrimitiveValue { + self.root + .get(slot / PAGE_SUBDIVISION_LEN) + .and_then(|inner| inner.as_ref()) + .map(|leaf| &leaf[slot % PAGE_SUBDIVISION_LEN]) + .unwrap_or(&PRIMITIVE_VALUE_EMPTY) + } + fn set(&mut self, slot: usize, value: PrimitiveValue) -> PrimitiveValue { + let root_index = slot / PAGE_SUBDIVISION_LEN; + let leaf_index = slot % PAGE_SUBDIVISION_LEN; + + if self.root.len() <= root_index { + self.root.resize_with(root_index + 1, || None); + } + let node = &mut self.root[root_index]; + + if let Some(leaf) = node { + let old = leaf[leaf_index]; + leaf[leaf_index] = value; + old + } else { + let mut leaf = [PrimitiveValue::empty(); PAGE_SUBDIVISION_LEN]; + leaf[leaf_index] = value; + self.root[root_index] = Some(Box::new(leaf)); + PrimitiveValue::empty() + } + } + + fn get_size(&self) -> usize { + self.root.iter().filter_map(|x| x.as_ref()).count() + * PAGE_SUBDIVISION_LEN + * std::mem::size_of::() + } +} + +impl PartialEq for MemoryPage { + fn eq(&self, other: &Self) -> bool { + for slot in 0..self.root.len().max(other.root.len()) * PAGE_SUBDIVISION_LEN { + if self.get(slot) != other.get(slot) { + return false; + } + } + true + } +} + +#[derive(Debug, Default, Clone)] +pub struct MemoryWrapper { + memory: Vec, +} + +impl PartialEq for MemoryWrapper { + fn eq(&self, other: &Self) -> bool { + let empty_page = MemoryPage::default(); + let empty_pages = std::iter::repeat(&empty_page); + self.memory + .iter() + .chain(empty_pages.clone()) + .zip(other.memory.iter().chain(empty_pages)) + .take(self.memory.len().max(other.memory.len())) + .all(|(a, b)| a == b) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct MemoryHistoryRecord { + pub page: usize, + pub slot: usize, + pub set_value: PrimitiveValue, +} + +impl MemoryWrapper { + pub fn ensure_page_exists(&mut self, page: usize) { + if self.memory.len() <= page { + // We don't need to record such events in history + // because all these vectors will be empty + self.memory.resize_with(page + 1, MemoryPage::default); + } + } + + pub fn dump_page_content_as_u256_words( + &self, + page_number: u32, + range: std::ops::Range, + ) -> Vec { + if let Some(page) = self.memory.get(page_number as usize) { + let mut result = vec![]; + for i in range { + result.push(*page.get(i as usize)); + } + result + } else { + vec![PrimitiveValue::empty(); range.len()] + } + } + + pub fn read_slot(&self, page: usize, slot: usize) -> &PrimitiveValue { + self.memory + .get(page) + .map(|page| page.get(slot)) + .unwrap_or(&PRIMITIVE_VALUE_EMPTY) + } + + pub fn get_size(&self) -> usize { + self.memory.iter().map(|page| page.get_size()).sum() + } +} + +impl WithHistory for MemoryWrapper { + type HistoryRecord = MemoryHistoryRecord; + type ReturnValue = PrimitiveValue; + + fn apply_historic_record( + &mut self, + item: MemoryHistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + let MemoryHistoryRecord { + page, + slot, + set_value, + } = item; + + self.ensure_page_exists(page); + let page_handle = self.memory.get_mut(page).unwrap(); + let prev_value = page_handle.set(slot, set_value); + + let undo = MemoryHistoryRecord { + page, + slot, + set_value: prev_value, + }; + + (undo, prev_value) + } +} + +impl HistoryRecorder { + pub fn write_to_memory( + &mut self, + page: usize, + slot: usize, + value: PrimitiveValue, + timestamp: Timestamp, + ) -> PrimitiveValue { + self.apply_historic_record( + MemoryHistoryRecord { + page, + slot, + set_value: value, + }, + timestamp, + ) + } + + pub fn clear_page(&mut self, page: usize, timestamp: Timestamp) { + self.mutate_history(|inner, history| { + if let Some(page_handle) = inner.memory.get(page) { + for (i, x) in page_handle.root.iter().enumerate() { + if let Some(slots) = x { + for (j, value) in slots.iter().enumerate() { + if *value != PrimitiveValue::empty() { + history.push(( + timestamp, + MemoryHistoryRecord { + page, + slot: PAGE_SUBDIVISION_LEN * i + j, + set_value: *value, + }, + )) + } + } + } + } + inner.memory[page] = MemoryPage::default(); + } + }); + } +} + +#[derive(Debug)] +pub struct StorageWrapper { + storage_ptr: StoragePtr, +} + +impl StorageWrapper { + pub fn new(storage_ptr: StoragePtr) -> Self { + Self { storage_ptr } + } + + pub fn get_ptr(&self) -> StoragePtr { + self.storage_ptr.clone() + } + + pub fn read_from_storage(&self, key: &StorageKey) -> U256 { + h256_to_u256(self.storage_ptr.borrow_mut().read_value(key)) + } +} + +#[derive(Debug, Clone)] +pub struct StorageHistoryRecord { + pub key: StorageKey, + pub value: U256, +} + +impl WithHistory for StorageWrapper { + type HistoryRecord = StorageHistoryRecord; + type ReturnValue = U256; + + fn apply_historic_record( + &mut self, + item: Self::HistoryRecord, + ) -> (Self::HistoryRecord, Self::ReturnValue) { + let prev_value = h256_to_u256( + self.storage_ptr + .borrow_mut() + .set_value(item.key, u256_to_h256(item.value)), + ); + + let reverse_item = StorageHistoryRecord { + key: item.key, + value: prev_value, + }; + + (reverse_item, prev_value) + } +} + +impl HistoryRecorder, H> { + pub fn read_from_storage(&self, key: &StorageKey) -> U256 { + self.inner.read_from_storage(key) + } + + pub fn write_to_storage(&mut self, key: StorageKey, value: U256, timestamp: Timestamp) -> U256 { + self.apply_historic_record(StorageHistoryRecord { key, value }, timestamp) + } + + /// Returns a pointer to the storage. + /// Note, that any changes done to the storage via this pointer + /// will NOT be recorded as its history. + pub fn get_ptr(&self) -> StoragePtr { + self.inner.get_ptr() + } +} + +#[cfg(test)] +mod tests { + use zk_evm_1_4_1::{aux_structures::Timestamp, vm_state::PrimitiveValue}; + use zksync_types::U256; + + use crate::vm_1_4_1::{ + old_vm::history_recorder::{HistoryRecorder, MemoryWrapper}, + HistoryDisabled, + }; + + #[test] + fn memory_equality() { + let mut a: HistoryRecorder = Default::default(); + let mut b = a.clone(); + let nonzero = U256::from_dec_str("123").unwrap(); + let different_value = U256::from_dec_str("1234").unwrap(); + + let write = |memory: &mut HistoryRecorder, value| { + memory.write_to_memory( + 17, + 34, + PrimitiveValue { + value, + is_pointer: false, + }, + Timestamp::empty(), + ); + }; + + assert_eq!(a, b); + + write(&mut b, nonzero); + assert_ne!(a, b); + + write(&mut a, different_value); + assert_ne!(a, b); + + write(&mut a, nonzero); + assert_eq!(a, b); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/memory.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/memory.rs new file mode 100644 index 000000000000..3454b603c5d6 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/memory.rs @@ -0,0 +1,327 @@ +use zk_evm_1_4_1::{ + abstractions::{Memory, MemoryType}, + aux_structures::{MemoryPage, MemoryQuery, Timestamp}, + vm_state::PrimitiveValue, + zkevm_opcode_defs::FatPointer, +}; +use zksync_types::U256; + +use crate::vm_1_4_1::old_vm::{ + history_recorder::{ + FramedStack, HistoryEnabled, HistoryMode, IntFrameManagerWithHistory, MemoryWithHistory, + MemoryWrapper, WithHistory, + }, + oracles::OracleWithHistory, + utils::{aux_heap_page_from_base, heap_page_from_base, stack_page_from_base}, +}; + +#[derive(Debug, Clone, PartialEq)] +pub struct SimpleMemory { + memory: MemoryWithHistory, + observable_pages: IntFrameManagerWithHistory, +} + +impl Default for SimpleMemory { + fn default() -> Self { + let mut memory: MemoryWithHistory = Default::default(); + memory.mutate_history(|_, h| h.reserve(607)); + Self { + memory, + observable_pages: Default::default(), + } + } +} + +impl OracleWithHistory for SimpleMemory { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.memory.rollback_to_timestamp(timestamp); + self.observable_pages.rollback_to_timestamp(timestamp); + } +} + +impl SimpleMemory { + pub fn populate(&mut self, elements: Vec<(u32, Vec)>, timestamp: Timestamp) { + for (page, values) in elements.into_iter() { + for (i, value) in values.into_iter().enumerate() { + let value = PrimitiveValue { + value, + is_pointer: false, + }; + self.memory + .write_to_memory(page as usize, i, value, timestamp); + } + } + } + + pub fn populate_page( + &mut self, + page: usize, + elements: Vec<(usize, U256)>, + timestamp: Timestamp, + ) { + elements.into_iter().for_each(|(offset, value)| { + let value = PrimitiveValue { + value, + is_pointer: false, + }; + + self.memory.write_to_memory(page, offset, value, timestamp); + }); + } + + pub fn dump_page_content_as_u256_words( + &self, + page: u32, + range: std::ops::Range, + ) -> Vec { + self.memory + .inner() + .dump_page_content_as_u256_words(page, range) + .into_iter() + .map(|v| v.value) + .collect() + } + + pub fn read_slot(&self, page: usize, slot: usize) -> &PrimitiveValue { + self.memory.inner().read_slot(page, slot) + } + + // This method should be used with relatively small lengths, since + // we don't heavily optimize here for cases with long lengths + pub fn read_unaligned_bytes(&self, page: usize, start: usize, length: usize) -> Vec { + if length == 0 { + return vec![]; + } + + let end = start + length - 1; + + let mut current_word = start / 32; + let mut result = vec![]; + while current_word * 32 <= end { + let word_value = self.read_slot(page, current_word).value; + let word_value = { + let mut bytes: Vec = vec![0u8; 32]; + word_value.to_big_endian(&mut bytes); + bytes + }; + + result.extend(extract_needed_bytes_from_word( + word_value, + current_word, + start, + end, + )); + + current_word += 1; + } + + assert_eq!(result.len(), length); + + result + } + + pub(crate) fn get_size(&self) -> usize { + // Hashmap memory overhead is neglected. + let memory_size = self.memory.inner().get_size(); + let observable_pages_size = self.observable_pages.inner().get_size(); + + memory_size + observable_pages_size + } + + pub fn get_history_size(&self) -> usize { + let memory_size = self.memory.borrow_history(|h| h.len(), 0) + * std::mem::size_of::<::HistoryRecord>(); + let observable_pages_size = self.observable_pages.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + + memory_size + observable_pages_size + } + + pub fn delete_history(&mut self) { + self.memory.delete_history(); + self.observable_pages.delete_history(); + } +} + +impl Memory for SimpleMemory { + fn execute_partial_query( + &mut self, + _monotonic_cycle_counter: u32, + mut query: MemoryQuery, + ) -> MemoryQuery { + match query.location.memory_type { + MemoryType::Stack => {} + MemoryType::Heap | MemoryType::AuxHeap => { + // The following assertion works fine even when doing a read + // from heap through pointer, since `value_is_pointer` can only be set to + // `true` during memory writes. + assert!( + !query.value_is_pointer, + "Pointers can only be stored on stack" + ); + } + MemoryType::FatPointer => { + assert!(!query.rw_flag); + assert!( + !query.value_is_pointer, + "Pointers can only be stored on stack" + ); + } + MemoryType::Code => { + unreachable!("code should be through specialized query"); + } + } + + let page = query.location.page.0 as usize; + let slot = query.location.index.0 as usize; + + if query.rw_flag { + self.memory.write_to_memory( + page, + slot, + PrimitiveValue { + value: query.value, + is_pointer: query.value_is_pointer, + }, + query.timestamp, + ); + } else { + let current_value = self.read_slot(page, slot); + query.value = current_value.value; + query.value_is_pointer = current_value.is_pointer; + } + + query + } + + fn specialized_code_query( + &mut self, + _monotonic_cycle_counter: u32, + mut query: MemoryQuery, + ) -> MemoryQuery { + assert_eq!(query.location.memory_type, MemoryType::Code); + assert!( + !query.value_is_pointer, + "Pointers are not used for decommmits" + ); + + let page = query.location.page.0 as usize; + let slot = query.location.index.0 as usize; + + if query.rw_flag { + self.memory.write_to_memory( + page, + slot, + PrimitiveValue { + value: query.value, + is_pointer: query.value_is_pointer, + }, + query.timestamp, + ); + } else { + let current_value = self.read_slot(page, slot); + query.value = current_value.value; + query.value_is_pointer = current_value.is_pointer; + } + + query + } + + fn read_code_query( + &self, + _monotonic_cycle_counter: u32, + mut query: MemoryQuery, + ) -> MemoryQuery { + assert_eq!(query.location.memory_type, MemoryType::Code); + assert!( + !query.value_is_pointer, + "Pointers are not used for decommmits" + ); + assert!(!query.rw_flag, "Only read queries can be processed"); + + let page = query.location.page.0 as usize; + let slot = query.location.index.0 as usize; + + let current_value = self.read_slot(page, slot); + query.value = current_value.value; + query.value_is_pointer = current_value.is_pointer; + + query + } + + fn start_global_frame( + &mut self, + _current_base_page: MemoryPage, + new_base_page: MemoryPage, + calldata_fat_pointer: FatPointer, + timestamp: Timestamp, + ) { + // Besides the calldata page, we also formally include the current stack + // page, heap page and aux heap page. + // The code page will be always left observable, so we don't include it here. + self.observable_pages.push_frame(timestamp); + self.observable_pages.extend_frame( + vec![ + calldata_fat_pointer.memory_page, + stack_page_from_base(new_base_page).0, + heap_page_from_base(new_base_page).0, + aux_heap_page_from_base(new_base_page).0, + ], + timestamp, + ); + } + + fn finish_global_frame( + &mut self, + base_page: MemoryPage, + returndata_fat_pointer: FatPointer, + timestamp: Timestamp, + ) { + // Safe to unwrap here, since `finish_global_frame` is never called with empty stack + let current_observable_pages = self.observable_pages.inner().current_frame(); + let returndata_page = returndata_fat_pointer.memory_page; + + for &page in current_observable_pages { + // If the page's number is greater than or equal to the `base_page`, + // it means that it was created by the internal calls of this contract. + // We need to add this check as the calldata pointer is also part of the + // observable pages. + if page >= base_page.0 && page != returndata_page { + self.memory.clear_page(page as usize, timestamp); + } + } + + self.observable_pages.clear_frame(timestamp); + self.observable_pages.merge_frame(timestamp); + + self.observable_pages + .push_to_frame(returndata_page, timestamp); + } +} + +// It is expected that there is some intersection between `[word_number*32..word_number*32+31]` and `[start, end]` +fn extract_needed_bytes_from_word( + word_value: Vec, + word_number: usize, + start: usize, + end: usize, +) -> Vec { + let word_start = word_number * 32; + let word_end = word_start + 31; // Note, that at `word_start + 32` a new word already starts + + let intersection_left = std::cmp::max(word_start, start); + let intersection_right = std::cmp::min(word_end, end); + + if intersection_right < intersection_left { + vec![] + } else { + let start_bytes = intersection_left - word_start; + let to_take = intersection_right - intersection_left + 1; + + word_value + .into_iter() + .skip(start_bytes) + .take(to_take) + .collect() + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/mod.rs new file mode 100644 index 000000000000..afade1984614 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/mod.rs @@ -0,0 +1,8 @@ +/// This module contains the parts from old VM implementation, which were not changed during the vm implementation. +/// It should be refactored and removed in the future. +pub(crate) mod event_sink; +pub(crate) mod events; +pub(crate) mod history_recorder; +pub(crate) mod memory; +pub(crate) mod oracles; +pub(crate) mod utils; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/decommitter.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/decommitter.rs new file mode 100644 index 000000000000..c301b3cb18b7 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/decommitter.rs @@ -0,0 +1,235 @@ +use std::{collections::HashMap, fmt::Debug}; + +use zk_evm_1_4_1::{ + abstractions::{DecommittmentProcessor, Memory, MemoryType}, + aux_structures::{ + DecommittmentQuery, MemoryIndex, MemoryLocation, MemoryPage, MemoryQuery, Timestamp, + }, +}; +use zksync_state::{ReadStorage, StoragePtr}; +use zksync_types::U256; +use zksync_utils::{bytecode::bytecode_len_in_words, bytes_to_be_words, u256_to_h256}; + +use super::OracleWithHistory; +use crate::vm_1_4_1::old_vm::history_recorder::{ + HistoryEnabled, HistoryMode, HistoryRecorder, WithHistory, +}; +/// The main job of the DecommiterOracle is to implement the DecommittmentProcessor trait - that is +/// used by the VM to 'load' bytecodes into memory. +#[derive(Debug)] +pub struct DecommitterOracle { + /// Pointer that enables to read contract bytecodes from the database. + storage: StoragePtr, + /// The cache of bytecodes that the bootloader "knows", but that are not necessarily in the database. + /// And it is also used as a database cache. + pub known_bytecodes: HistoryRecorder>, H>, + /// Stores pages of memory where certain code hashes have already been decommitted. + /// It is expected that they all are present in the DB. + // `decommitted_code_hashes` history is necessary + pub decommitted_code_hashes: HistoryRecorder, HistoryEnabled>, + /// Stores history of decommitment requests. + decommitment_requests: HistoryRecorder, H>, +} + +impl DecommitterOracle { + pub fn new(storage: StoragePtr) -> Self { + Self { + storage, + known_bytecodes: HistoryRecorder::default(), + decommitted_code_hashes: HistoryRecorder::default(), + decommitment_requests: HistoryRecorder::default(), + } + } + + /// Gets the bytecode for a given hash (either from storage, or from 'known_bytecodes' that were populated by `populate` method). + /// Panics if bytecode doesn't exist. + pub fn get_bytecode(&mut self, hash: U256, timestamp: Timestamp) -> Vec { + let entry = self.known_bytecodes.inner().get(&hash); + + match entry { + Some(x) => x.clone(), + None => { + // It is ok to panic here, since the decommitter is never called directly by + // the users and always called by the VM. VM will never let decommit the + // code hash which we didn't previously claim to know the preimage of. + let value = self + .storage + .borrow_mut() + .load_factory_dep(u256_to_h256(hash)) + .expect("Trying to decode unexisting hash"); + + let value = bytes_to_be_words(value); + self.known_bytecodes.insert(hash, value.clone(), timestamp); + value + } + } + } + + /// Adds additional bytecodes. They will take precedent over the bytecodes from storage. + pub fn populate(&mut self, bytecodes: Vec<(U256, Vec)>, timestamp: Timestamp) { + for (hash, bytecode) in bytecodes { + self.known_bytecodes.insert(hash, bytecode, timestamp); + } + } + + pub fn get_used_bytecode_hashes(&self) -> Vec { + self.decommitted_code_hashes + .inner() + .iter() + .map(|item| *item.0) + .collect() + } + + pub fn get_decommitted_bytecodes_after_timestamp(&self, timestamp: Timestamp) -> usize { + // Note, that here we rely on the fact that for each used bytecode + // there is one and only one corresponding event in the history of it. + self.decommitted_code_hashes + .history() + .iter() + .rev() + .take_while(|(t, _)| *t >= timestamp) + .count() + } + + pub fn get_decommitted_code_hashes_with_history( + &self, + ) -> &HistoryRecorder, HistoryEnabled> { + &self.decommitted_code_hashes + } + + /// Returns the storage handle. Used only in tests. + pub fn get_storage(&self) -> StoragePtr { + self.storage.clone() + } + + /// Measures the amount of memory used by this Oracle (used for metrics only). + pub(crate) fn get_size(&self) -> usize { + // Hashmap memory overhead is neglected. + let known_bytecodes_size = self + .known_bytecodes + .inner() + .iter() + .map(|(_, value)| value.len() * std::mem::size_of::()) + .sum::(); + let decommitted_code_hashes_size = + self.decommitted_code_hashes.inner().len() * std::mem::size_of::<(U256, u32)>(); + + known_bytecodes_size + decommitted_code_hashes_size + } + + pub(crate) fn get_history_size(&self) -> usize { + let known_bytecodes_stack_size = self.known_bytecodes.borrow_history(|h| h.len(), 0) + * std::mem::size_of::<> as WithHistory>::HistoryRecord>(); + let known_bytecodes_heap_size = self.known_bytecodes.borrow_history( + |h| { + h.iter() + .map(|(_, event)| { + if let Some(bytecode) = event.value.as_ref() { + bytecode.len() * std::mem::size_of::() + } else { + 0 + } + }) + .sum::() + }, + 0, + ); + let decommitted_code_hashes_size = + self.decommitted_code_hashes.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + + known_bytecodes_stack_size + known_bytecodes_heap_size + decommitted_code_hashes_size + } + + pub fn delete_history(&mut self) { + self.decommitted_code_hashes.delete_history(); + self.known_bytecodes.delete_history(); + self.decommitment_requests.delete_history(); + } +} + +impl OracleWithHistory for DecommitterOracle { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.decommitted_code_hashes + .rollback_to_timestamp(timestamp); + self.known_bytecodes.rollback_to_timestamp(timestamp); + self.decommitment_requests.rollback_to_timestamp(timestamp); + } +} + +impl DecommittmentProcessor + for DecommitterOracle +{ + /// Loads a given bytecode hash into memory (see trait description for more details). + fn decommit_into_memory( + &mut self, + monotonic_cycle_counter: u32, + mut partial_query: DecommittmentQuery, + memory: &mut M, + ) -> Result< + ( + zk_evm_1_4_1::aux_structures::DecommittmentQuery, + Option>, + ), + anyhow::Error, + > { + self.decommitment_requests.push((), partial_query.timestamp); + // First - check if we didn't fetch this bytecode in the past. + // If we did - we can just return the page that we used before (as the memory is readonly). + if let Some(memory_page) = self + .decommitted_code_hashes + .inner() + .get(&partial_query.hash) + .copied() + { + partial_query.is_fresh = false; + partial_query.memory_page = MemoryPage(memory_page); + partial_query.decommitted_length = + bytecode_len_in_words(&u256_to_h256(partial_query.hash)); + + Ok((partial_query, None)) + } else { + // We are fetching a fresh bytecode that we didn't read before. + let values = self.get_bytecode(partial_query.hash, partial_query.timestamp); + let page_to_use = partial_query.memory_page; + let timestamp = partial_query.timestamp; + partial_query.decommitted_length = values.len() as u16; + partial_query.is_fresh = true; + + // Create a template query, that we'll use for writing into memory. + // value & index are set to 0 - as they will be updated in the inner loop below. + let mut tmp_q = MemoryQuery { + timestamp, + location: MemoryLocation { + memory_type: MemoryType::Code, + page: page_to_use, + index: MemoryIndex(0), + }, + value: U256::zero(), + value_is_pointer: false, + rw_flag: true, + }; + self.decommitted_code_hashes + .insert(partial_query.hash, page_to_use.0, timestamp); + + // Copy the bytecode (that is stored in 'values' Vec) into the memory page. + if B { + for (i, value) in values.iter().enumerate() { + tmp_q.location.index = MemoryIndex(i as u32); + tmp_q.value = *value; + memory.specialized_code_query(monotonic_cycle_counter, tmp_q); + } + // If we're in the witness mode - we also have to return the values. + Ok((partial_query, Some(values))) + } else { + for (i, value) in values.into_iter().enumerate() { + tmp_q.location.index = MemoryIndex(i as u32); + tmp_q.value = value; + memory.specialized_code_query(monotonic_cycle_counter, tmp_q); + } + + Ok((partial_query, None)) + } + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/mod.rs new file mode 100644 index 000000000000..7d463ad082be --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/mod.rs @@ -0,0 +1,8 @@ +use zk_evm_1_4_1::aux_structures::Timestamp; + +pub(crate) mod decommitter; +pub(crate) mod precompile; + +pub(crate) trait OracleWithHistory { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/precompile.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/precompile.rs new file mode 100644 index 000000000000..3b58674acad3 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/oracles/precompile.rs @@ -0,0 +1,112 @@ +use std::convert::TryFrom; + +use zk_evm_1_4_1::{ + abstractions::{Memory, PrecompileCyclesWitness, PrecompilesProcessor}, + aux_structures::{LogQuery, MemoryQuery, Timestamp}, + zk_evm_abstractions::precompiles::{ecrecover, keccak256, sha256, PrecompileAddress}, +}; + +use super::OracleWithHistory; +use crate::vm_1_4_1::old_vm::history_recorder::{HistoryEnabled, HistoryMode, HistoryRecorder}; + +/// Wrap of DefaultPrecompilesProcessor that store queue +/// of timestamp when precompiles are called to be executed. +/// Number of precompiles per block is strictly limited, +/// saving timestamps allows us to check the exact number +/// of log queries, that were used during the tx execution. +#[derive(Debug, Clone)] +pub struct PrecompilesProcessorWithHistory { + pub timestamp_history: HistoryRecorder, H>, + pub precompile_cycles_history: HistoryRecorder, H>, +} + +impl Default for PrecompilesProcessorWithHistory { + fn default() -> Self { + Self { + timestamp_history: Default::default(), + precompile_cycles_history: Default::default(), + } + } +} + +impl OracleWithHistory for PrecompilesProcessorWithHistory { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.timestamp_history.rollback_to_timestamp(timestamp); + self.precompile_cycles_history + .rollback_to_timestamp(timestamp); + } +} + +impl PrecompilesProcessorWithHistory { + pub fn get_timestamp_history(&self) -> &Vec { + self.timestamp_history.inner() + } + + pub fn delete_history(&mut self) { + self.timestamp_history.delete_history(); + self.precompile_cycles_history.delete_history(); + } +} + +impl PrecompilesProcessor for PrecompilesProcessorWithHistory { + fn start_frame(&mut self) { + // there are no precompiles to rollback, do nothing + } + + fn execute_precompile( + &mut self, + monotonic_cycle_counter: u32, + query: LogQuery, + memory: &mut M, + ) -> Option<(Vec, Vec, PrecompileCyclesWitness)> { + // In the next line we same `query.timestamp` as both + // an operation in the history of precompiles processor and + // the time when this operation occurred. + // While slightly weird, it is done for consistency with other oracles + // where operations and timestamp have different types. + self.timestamp_history + .push(query.timestamp, query.timestamp); + + let address_low = u16::from_le_bytes([query.address.0[19], query.address.0[18]]); + if let Ok(precompile_address) = PrecompileAddress::try_from(address_low) { + let rounds = match precompile_address { + PrecompileAddress::Keccak256 => { + // pure function call, non-revertable + keccak256::keccak256_rounds_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + PrecompileAddress::SHA256 => { + // pure function call, non-revertable + sha256::sha256_rounds_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + PrecompileAddress::Ecrecover => { + // pure function call, non-revertable + ecrecover::ecrecover_function::( + monotonic_cycle_counter, + query, + memory, + ) + .0 + } + }; + + self.precompile_cycles_history + .push((precompile_address, rounds), query.timestamp); + }; + + None + } + + fn finish_frame(&mut self, _panicked: bool) { + // there are no revertible precompile yes, so we are ok + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/old_vm/utils.rs b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/utils.rs new file mode 100644 index 000000000000..3f63e9377c90 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/old_vm/utils.rs @@ -0,0 +1,212 @@ +use zk_evm_1_4_1::{ + aux_structures::{MemoryPage, Timestamp}, + vm_state::PrimitiveValue, + zkevm_opcode_defs::{ + decoding::{AllowedPcOrImm, EncodingModeProduction, VmEncodingMode}, + FatPointer, RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, + }, +}; +use zksync_state::WriteStorage; +use zksync_types::{Address, U256}; + +use crate::vm_1_4_1::{old_vm::memory::SimpleMemory, types::internals::ZkSyncVmState, HistoryMode}; + +#[derive(Debug, Clone)] +pub(crate) enum VmExecutionResult { + Ok(Vec), + Revert(Vec), + Panic, + MostLikelyDidNotFinish(Address, u16), +} + +pub(crate) const fn stack_page_from_base(base: MemoryPage) -> MemoryPage { + MemoryPage(base.0 + 1) +} + +pub(crate) const fn heap_page_from_base(base: MemoryPage) -> MemoryPage { + MemoryPage(base.0 + 2) +} + +pub(crate) const fn aux_heap_page_from_base(base: MemoryPage) -> MemoryPage { + MemoryPage(base.0 + 3) +} + +pub(crate) trait FixedLengthIterator<'a, I: 'a, const N: usize>: Iterator +where + Self: 'a, +{ + fn next(&mut self) -> Option<::Item> { + ::next(self) + } +} + +pub(crate) trait IntoFixedLengthByteIterator { + type IntoIter: FixedLengthIterator<'static, u8, N>; + fn into_le_iter(self) -> Self::IntoIter; + fn into_be_iter(self) -> Self::IntoIter; +} + +pub(crate) struct FixedBufferValueIterator { + iter: std::array::IntoIter, +} + +impl Iterator for FixedBufferValueIterator { + type Item = T; + fn next(&mut self) -> Option { + self.iter.next() + } +} + +impl FixedLengthIterator<'static, T, N> + for FixedBufferValueIterator +{ +} + +impl IntoFixedLengthByteIterator<32> for U256 { + type IntoIter = FixedBufferValueIterator; + fn into_le_iter(self) -> Self::IntoIter { + let mut buffer = [0u8; 32]; + self.to_little_endian(&mut buffer); + + FixedBufferValueIterator { + iter: IntoIterator::into_iter(buffer), + } + } + + fn into_be_iter(self) -> Self::IntoIter { + let mut buffer = [0u8; 32]; + self.to_big_endian(&mut buffer); + + FixedBufferValueIterator { + iter: IntoIterator::into_iter(buffer), + } + } +} + +/// Receives sorted slice of timestamps. +/// Returns count of timestamps that are greater than or equal to `from_timestamp`. +/// Works in O(log(sorted_timestamps.len())). +pub(crate) fn precompile_calls_count_after_timestamp( + sorted_timestamps: &[Timestamp], + from_timestamp: Timestamp, +) -> usize { + sorted_timestamps.len() - sorted_timestamps.partition_point(|t| *t < from_timestamp) +} + +pub(crate) fn vm_may_have_ended_inner( + vm: &ZkSyncVmState, +) -> Option { + let execution_has_ended = vm.execution_has_ended(); + + let r1 = vm.local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; + let current_address = vm.local_state.callstack.get_current_stack().this_address; + + let outer_eh_location = >::PcOrImm::MAX.as_u64(); + match ( + execution_has_ended, + vm.local_state.callstack.get_current_stack().pc.as_u64(), + ) { + (true, 0) => { + let returndata = dump_memory_page_using_primitive_value(&vm.memory, r1); + + Some(VmExecutionResult::Ok(returndata)) + } + (false, _) => None, + (true, l) if l == outer_eh_location => { + // check `r1,r2,r3` + if vm.local_state.flags.overflow_or_less_than_flag { + Some(VmExecutionResult::Panic) + } else { + let returndata = dump_memory_page_using_primitive_value(&vm.memory, r1); + Some(VmExecutionResult::Revert(returndata)) + } + } + (_, a) => Some(VmExecutionResult::MostLikelyDidNotFinish( + current_address, + a as u16, + )), + } +} + +pub(crate) fn dump_memory_page_using_primitive_value( + memory: &SimpleMemory, + ptr: PrimitiveValue, +) -> Vec { + if !ptr.is_pointer { + return vec![]; + } + let fat_ptr = FatPointer::from_u256(ptr.value); + dump_memory_page_using_fat_pointer(memory, fat_ptr) +} + +pub(crate) fn dump_memory_page_using_fat_pointer( + memory: &SimpleMemory, + fat_ptr: FatPointer, +) -> Vec { + dump_memory_page_by_offset_and_length( + memory, + fat_ptr.memory_page, + (fat_ptr.start + fat_ptr.offset) as usize, + (fat_ptr.length - fat_ptr.offset) as usize, + ) +} + +pub(crate) fn dump_memory_page_by_offset_and_length( + memory: &SimpleMemory, + page: u32, + offset: usize, + length: usize, +) -> Vec { + assert!(offset < (1u32 << 24) as usize); + assert!(length < (1u32 << 24) as usize); + let mut dump = Vec::with_capacity(length); + if length == 0 { + return dump; + } + + let first_word = offset / 32; + let end_byte = offset + length; + let mut last_word = end_byte / 32; + if end_byte % 32 != 0 { + last_word += 1; + } + + let unalignment = offset % 32; + + let page_part = + memory.dump_page_content_as_u256_words(page, (first_word as u32)..(last_word as u32)); + + let mut is_first = true; + let mut remaining = length; + for word in page_part.into_iter() { + let it = word.into_be_iter(); + if is_first { + is_first = false; + let it = it.skip(unalignment); + for next in it { + if remaining > 0 { + dump.push(next); + remaining -= 1; + } + } + } else { + for next in it { + if remaining > 0 { + dump.push(next); + remaining -= 1; + } + } + } + } + + assert_eq!( + dump.len(), + length, + "tried to dump with offset {}, length {}, got a bytestring of length {}", + offset, + length, + dump.len() + ); + + dump +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/oracles/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/oracles/mod.rs new file mode 100644 index 000000000000..b21c842572fe --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/oracles/mod.rs @@ -0,0 +1 @@ +pub(crate) mod storage; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/oracles/storage.rs b/core/lib/multivm/src/versions/vm_1_4_1/oracles/storage.rs new file mode 100644 index 000000000000..df0283c6bcc8 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/oracles/storage.rs @@ -0,0 +1,514 @@ +use std::collections::HashMap; + +use zk_evm_1_4_1::{ + abstractions::{RefundType, RefundedAmounts, Storage as VmStorageOracle}, + aux_structures::{LogQuery, Timestamp}, + zkevm_opcode_defs::system_params::INITIAL_STORAGE_WRITE_PUBDATA_BYTES, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + utils::storage_key_for_eth_balance, + writes::{ + compression::compress_with_best_strategy, BYTES_PER_DERIVED_KEY, + BYTES_PER_ENUMERATION_INDEX, + }, + AccountTreeId, Address, StorageKey, StorageLogQueryType, BOOTLOADER_ADDRESS, U256, +}; +use zksync_utils::u256_to_h256; + +use crate::{ + glue::GlueInto, + vm_1_4_1::{ + old_vm::{ + history_recorder::{ + AppDataFrameManagerWithHistory, HashMapHistoryEvent, HistoryEnabled, HistoryMode, + HistoryRecorder, StorageWrapper, VectorHistoryEvent, WithHistory, + }, + oracles::OracleWithHistory, + }, + utils::logs::StorageLogQuery, + }, +}; + +// While the storage does not support different shards, it was decided to write the +// code of the StorageOracle with the shard parameters in mind. +pub(crate) fn triplet_to_storage_key(_shard_id: u8, address: Address, key: U256) -> StorageKey { + StorageKey::new(AccountTreeId::new(address), u256_to_h256(key)) +} + +pub(crate) fn storage_key_of_log(query: &LogQuery) -> StorageKey { + triplet_to_storage_key(query.shard_id, query.address, query.key) +} + +#[derive(Debug)] +pub struct StorageOracle { + // Access to the persistent storage. Please note that it + // is used only for read access. All the actual writes happen + // after the execution ended. + pub(crate) storage: HistoryRecorder, H>, + + pub(crate) frames_stack: AppDataFrameManagerWithHistory, H>, + + // The changes that have been paid for in previous transactions. + // It is a mapping from storage key to the number of *bytes* that was paid by the user + // to cover this slot. + pub(crate) pre_paid_changes: HistoryRecorder, H>, + + // The changes that have been paid for in the current transaction + pub(crate) paid_changes: HistoryRecorder, H>, + + // The map that contains all the first values read from storage for each slot. + // While formally it does not have to be capable of rolling back, we still do it to avoid memory bloat + // for unused slots. + pub(crate) initial_values: HistoryRecorder, H>, + + // Storage refunds that oracle has returned in `estimate_refunds_for_write`. + pub(crate) returned_refunds: HistoryRecorder, H>, + + // Keeps track of storage keys that were ever written to. + pub(crate) written_keys: HistoryRecorder, HistoryEnabled>, + // Keeps track of storage keys that were ever read. + pub(crate) read_keys: HistoryRecorder, HistoryEnabled>, +} + +impl OracleWithHistory for StorageOracle { + fn rollback_to_timestamp(&mut self, timestamp: Timestamp) { + self.storage.rollback_to_timestamp(timestamp); + self.frames_stack.rollback_to_timestamp(timestamp); + self.pre_paid_changes.rollback_to_timestamp(timestamp); + self.paid_changes.rollback_to_timestamp(timestamp); + self.initial_values.rollback_to_timestamp(timestamp); + self.returned_refunds.rollback_to_timestamp(timestamp); + self.written_keys.rollback_to_timestamp(timestamp); + self.read_keys.rollback_to_timestamp(timestamp); + } +} + +impl StorageOracle { + pub fn new(storage: StoragePtr) -> Self { + Self { + storage: HistoryRecorder::from_inner(StorageWrapper::new(storage)), + frames_stack: Default::default(), + pre_paid_changes: Default::default(), + paid_changes: Default::default(), + initial_values: Default::default(), + returned_refunds: Default::default(), + written_keys: Default::default(), + read_keys: Default::default(), + } + } + + pub fn delete_history(&mut self) { + self.storage.delete_history(); + self.frames_stack.delete_history(); + self.pre_paid_changes.delete_history(); + self.paid_changes.delete_history(); + self.initial_values.delete_history(); + self.returned_refunds.delete_history(); + self.written_keys.delete_history(); + self.read_keys.delete_history(); + } + + fn is_storage_key_free(&self, key: &StorageKey) -> bool { + key.address() == &zksync_system_constants::SYSTEM_CONTEXT_ADDRESS + || *key == storage_key_for_eth_balance(&BOOTLOADER_ADDRESS) + } + + fn get_initial_value(&self, storage_key: &StorageKey) -> Option { + self.initial_values.inner().get(storage_key).copied() + } + + fn set_initial_value(&mut self, storage_key: &StorageKey, value: U256, timestamp: Timestamp) { + if !self.initial_values.inner().contains_key(storage_key) { + self.initial_values.insert(*storage_key, value, timestamp); + } + } + + fn read_value(&mut self, mut query: LogQuery) -> LogQuery { + let key = triplet_to_storage_key(query.shard_id, query.address, query.key); + + if !self.read_keys.inner().contains_key(&key) { + self.read_keys.insert(key, (), query.timestamp); + } + let current_value = self.storage.read_from_storage(&key); + + query.read_value = current_value; + + self.set_initial_value(&key, current_value, query.timestamp); + + self.frames_stack.push_forward( + Box::new(StorageLogQuery { + log_query: query.glue_into(), + log_type: StorageLogQueryType::Read, + }), + query.timestamp, + ); + + query + } + + fn write_value(&mut self, query: LogQuery) -> LogQuery { + let key = triplet_to_storage_key(query.shard_id, query.address, query.key); + if !self.written_keys.inner().contains_key(&key) { + self.written_keys.insert(key, (), query.timestamp); + } + let current_value = + self.storage + .write_to_storage(key, query.written_value, query.timestamp); + + let is_initial_write = self.storage.get_ptr().borrow_mut().is_write_initial(&key); + let log_query_type = if is_initial_write { + StorageLogQueryType::InitialWrite + } else { + StorageLogQueryType::RepeatedWrite + }; + + self.set_initial_value(&key, current_value, query.timestamp); + + let mut storage_log_query = StorageLogQuery { + log_query: query.glue_into(), + log_type: log_query_type, + }; + self.frames_stack + .push_forward(Box::new(storage_log_query), query.timestamp); + storage_log_query.log_query.rollback = true; + self.frames_stack + .push_rollback(Box::new(storage_log_query), query.timestamp); + storage_log_query.log_query.rollback = false; + + query + } + + // Returns the amount of funds that has been already paid for writes into the storage slot + fn prepaid_for_write(&self, storage_key: &StorageKey) -> u32 { + self.paid_changes + .inner() + .get(storage_key) + .copied() + .unwrap_or_else(|| { + self.pre_paid_changes + .inner() + .get(storage_key) + .copied() + .unwrap_or(0) + }) + } + + // Remembers the changes that have been paid for in the current transaction. + // It also returns how much pubdata did the user pay for and how much was actually published. + pub(crate) fn save_paid_changes(&mut self, timestamp: Timestamp) -> u32 { + let mut published = 0; + + let modified_keys = self + .paid_changes + .inner() + .iter() + .map(|(k, v)| (*k, *v)) + .collect::>(); + + for (key, _) in modified_keys { + // It is expected that for each slot for which we have paid changes, there is some + // first slot value already read. + let first_slot_value = self.initial_values.inner().get(&key).copied().unwrap(); + + // This is the value has been written to the storage slot at the end. + let current_slot_value = self.storage.read_from_storage(&key); + + let required_pubdata = + self.base_price_for_write(&key, first_slot_value, current_slot_value); + + // We assume that `prepaid_for_slot` represents both the number of pubdata published and the number of bytes paid by the previous transactions + // as they should be identical. + let prepaid_for_slot = self + .pre_paid_changes + .inner() + .get(&key) + .copied() + .unwrap_or_default(); + + published += required_pubdata.saturating_sub(prepaid_for_slot); + + // We remove the slot from the paid changes and move to the pre-paid changes as + // the transaction ends. + self.paid_changes.remove(key, timestamp); + self.pre_paid_changes + .insert(key, prepaid_for_slot.max(required_pubdata), timestamp); + } + + published + } + + fn base_price_for_write_query(&self, query: &LogQuery) -> u32 { + let storage_key = storage_key_of_log(query); + + let initial_value = self + .get_initial_value(&storage_key) + .unwrap_or(self.storage.read_from_storage(&storage_key)); + + self.base_price_for_write(&storage_key, initial_value, query.written_value) + } + + pub(crate) fn base_price_for_write( + &self, + storage_key: &StorageKey, + prev_value: U256, + new_value: U256, + ) -> u32 { + if self.is_storage_key_free(storage_key) || prev_value == new_value { + return 0; + } + + let is_initial_write = self + .storage + .get_ptr() + .borrow_mut() + .is_write_initial(storage_key); + + get_pubdata_price_bytes(prev_value, new_value, is_initial_write) + } + + // Returns the price of the update in terms of pubdata bytes. + // TODO (SMA-1701): update VM to accept gas instead of pubdata. + fn value_update_price(&mut self, query: &LogQuery) -> u32 { + let storage_key = storage_key_of_log(query); + + let base_cost = self.base_price_for_write_query(query); + + let initial_value = self + .get_initial_value(&storage_key) + .unwrap_or(self.storage.read_from_storage(&storage_key)); + + self.set_initial_value(&storage_key, initial_value, query.timestamp); + + let already_paid = self.prepaid_for_write(&storage_key); + + if base_cost <= already_paid { + // Some other transaction has already paid for this slot, no need to pay anything + 0u32 + } else { + base_cost - already_paid + } + } + + /// Returns storage log queries from current frame where `log.log_query.timestamp >= from_timestamp`. + pub(crate) fn storage_log_queries_after_timestamp( + &self, + from_timestamp: Timestamp, + ) -> &[Box] { + let logs = self.frames_stack.forward().current_frame(); + + // Select all of the last elements where `l.log_query.timestamp >= from_timestamp`. + // Note, that using binary search here is dangerous, because the logs are not sorted by timestamp. + logs.rsplit(|l| l.log_query.timestamp < from_timestamp.glue_into()) + .next() + .unwrap_or(&[]) + } + + pub(crate) fn get_final_log_queries(&self) -> Vec { + assert_eq!( + self.frames_stack.len(), + 1, + "VM finished execution in unexpected state" + ); + + self.frames_stack + .forward() + .current_frame() + .iter() + .map(|x| **x) + .collect() + } + + pub(crate) fn get_size(&self) -> usize { + let frames_stack_size = self.frames_stack.get_size(); + let paid_changes_size = + self.paid_changes.inner().len() * std::mem::size_of::<(StorageKey, u32)>(); + + frames_stack_size + paid_changes_size + } + + pub(crate) fn get_history_size(&self) -> usize { + let storage_size = self.storage.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + let frames_stack_size = self.frames_stack.get_history_size(); + let paid_changes_size = self.paid_changes.borrow_history(|h| h.len(), 0) + * std::mem::size_of::< as WithHistory>::HistoryRecord>(); + storage_size + frames_stack_size + paid_changes_size + } +} + +impl VmStorageOracle for StorageOracle { + // Perform a storage read/write access by taking an partially filled query + // and returning filled query and cold/warm marker for pricing purposes + fn execute_partial_query( + &mut self, + _monotonic_cycle_counter: u32, + mut query: LogQuery, + ) -> LogQuery { + // ``` + // tracing::trace!( + // "execute partial query cyc {:?} addr {:?} key {:?}, rw {:?}, wr {:?}, tx {:?}", + // _monotonic_cycle_counter, + // query.address, + // query.key, + // query.rw_flag, + // query.written_value, + // query.tx_number_in_block + // ); + // ``` + assert!(!query.rollback); + if query.rw_flag { + // The number of bytes that have been compensated by the user to perform this write + let storage_key = storage_key_of_log(&query); + let read_value = self.storage.read_from_storage(&storage_key); + query.read_value = read_value; + + // It is considered that the user has paid for the whole base price for the writes + let to_pay_by_user = self.base_price_for_write_query(&query); + let prepaid = self.prepaid_for_write(&storage_key); + + if to_pay_by_user > prepaid { + self.paid_changes.apply_historic_record( + HashMapHistoryEvent { + key: storage_key, + value: Some(to_pay_by_user), + }, + query.timestamp, + ); + } + self.write_value(query) + } else { + self.read_value(query) + } + } + + // We can return the size of the refund before each storage query. + // Note, that while the `RefundType` allows to provide refunds both in + // `ergs` and `pubdata`, only refunds in pubdata will be compensated for the users + fn estimate_refunds_for_write( + &mut self, // to avoid any hacks inside, like prefetch + _monotonic_cycle_counter: u32, + partial_query: &LogQuery, + ) -> RefundType { + let storage_key = storage_key_of_log(partial_query); + let mut partial_query = *partial_query; + let read_value = self.storage.read_from_storage(&storage_key); + partial_query.read_value = read_value; + + let price_to_pay = self + .value_update_price(&partial_query) + .min(INITIAL_STORAGE_WRITE_PUBDATA_BYTES as u32); + + let refund = RefundType::RepeatedWrite(RefundedAmounts { + ergs: 0, + // `INITIAL_STORAGE_WRITE_PUBDATA_BYTES` is the default amount of pubdata bytes the user pays for. + pubdata_bytes: (INITIAL_STORAGE_WRITE_PUBDATA_BYTES as u32) - price_to_pay, + }); + self.returned_refunds.apply_historic_record( + VectorHistoryEvent::Push(refund.pubdata_refund()), + partial_query.timestamp, + ); + + refund + } + + // Indicate a start of execution frame for rollback purposes + fn start_frame(&mut self, timestamp: Timestamp) { + self.frames_stack.push_frame(timestamp); + } + + // Indicate that execution frame went out from the scope, so we can + // log the history and either rollback immediately or keep records to rollback later + fn finish_frame(&mut self, timestamp: Timestamp, panicked: bool) { + // If we panic then we append forward and rollbacks to the forward of parent, + // otherwise we place rollbacks of child before rollbacks of the parent + if panicked { + // perform actual rollback + for query in self.frames_stack.rollback().current_frame().iter().rev() { + let read_value = match query.log_type { + StorageLogQueryType::Read => { + // Having Read logs in rollback is not possible + tracing::warn!("Read log in rollback queue {:?}", query); + continue; + } + StorageLogQueryType::InitialWrite | StorageLogQueryType::RepeatedWrite => { + query.log_query.read_value + } + }; + + let LogQuery { written_value, .. } = query.log_query.glue_into(); + let key = triplet_to_storage_key( + query.log_query.shard_id, + query.log_query.address, + query.log_query.key, + ); + let current_value = self.storage.write_to_storage( + key, + // NOTE, that since it is a rollback query, + // the `read_value` is being set + read_value, timestamp, + ); + + // Additional validation that the current value was correct + // Unwrap is safe because the return value from `write_inner` is the previous value in this leaf. + // It is impossible to set leaf value to `None` + assert_eq!(current_value, written_value); + } + + self.frames_stack + .move_rollback_to_forward(|_| true, timestamp); + } + self.frames_stack.merge_frame(timestamp); + } +} + +/// Returns the number of bytes needed to publish a slot. +// Since we need to publish the state diffs onchain, for each of the updated storage slot +// we basically need to publish the following pair: `()`. +// For key we use the following optimization: +// - The first time we publish it, we use 32 bytes. +// Then, we remember a 8-byte id for this slot and assign it to it. We call this initial write. +// - The second time we publish it, we will use the 4/5 byte representation of this 8-byte instead of the 32 +// bytes of the entire key. +// For value compression, we use a metadata byte which holds the length of the value and the operation from the +// previous state to the new state, and the compressed value. The maximum for this is 33 bytes. +// Total bytes for initial writes then becomes 65 bytes and repeated writes becomes 38 bytes. +fn get_pubdata_price_bytes(initial_value: U256, final_value: U256, is_initial: bool) -> u32 { + // TODO (SMA-1702): take into account the content of the log query, i.e. values that contain mostly zeroes + // should cost less. + + let compressed_value_size = + compress_with_best_strategy(initial_value, final_value).len() as u32; + + if is_initial { + (BYTES_PER_DERIVED_KEY as u32) + compressed_value_size + } else { + (BYTES_PER_ENUMERATION_INDEX as u32) + compressed_value_size + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_get_pubdata_price_bytes() { + let initial_value = U256::default(); + let final_value = U256::from(92122); + let is_initial = true; + + let compression_len = 4; + + let initial_bytes_price = get_pubdata_price_bytes(initial_value, final_value, is_initial); + let repeated_bytes_price = get_pubdata_price_bytes(initial_value, final_value, !is_initial); + + assert_eq!( + initial_bytes_price, + (compression_len + BYTES_PER_DERIVED_KEY as usize) as u32 + ); + assert_eq!( + repeated_bytes_price, + (compression_len + BYTES_PER_ENUMERATION_INDEX as usize) as u32 + ); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/block_tip.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/block_tip.rs new file mode 100644 index 000000000000..ba699e7558b4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/block_tip.rs @@ -0,0 +1,284 @@ +use std::borrow::BorrowMut; + +use ethabi::Token; +use zk_evm_1_4_1::{ + aux_structures::Timestamp, zkevm_opcode_defs::system_params::MAX_PUBDATA_PER_BLOCK, +}; +use zksync_contracts::load_sys_contract; +use zksync_system_constants::{ + CONTRACT_FORCE_DEPLOYER_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS, L1_MESSENGER_ADDRESS, +}; +use zksync_types::{ + commitment::SerializeCommitment, get_code_key, l2_to_l1_log::L2ToL1Log, + writes::StateDiffRecord, Address, Execute, H256, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; + +use super::utils::{get_complex_upgrade_abi, read_complex_upgrade}; +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + constants::BOOTLOADER_BATCH_TIP_OVERHEAD, + tests::tester::{get_empty_storage, InMemoryStorageView, VmTesterBuilder}, + tracers::PubdataTracer, + HistoryEnabled, TracerDispatcher, + }, +}; + +#[derive(Debug, Clone, Default)] +struct L1MessengerTestData { + l2_to_l1_logs: usize, + messages: Vec>, + bytecodes: Vec>, + state_diffs: Vec, +} + +struct MimicCallInfo { + to: Address, + who_to_mimic: Address, + data: Vec, +} + +fn populate_mimic_calls(data: L1MessengerTestData) -> Vec { + let complex_upgrade = get_complex_upgrade_abi(); + let l1_messenger = load_sys_contract("L1Messenger"); + + let logs_mimic_calls = (0..data.l2_to_l1_logs).map(|_| MimicCallInfo { + to: L1_MESSENGER_ADDRESS, + who_to_mimic: KNOWN_CODES_STORAGE_ADDRESS, + data: l1_messenger + .function("sendL2ToL1Log") + .unwrap() + .encode_input(&[ + Token::Bool(false), + Token::FixedBytes(H256::random().0.to_vec()), + Token::FixedBytes(H256::random().0.to_vec()), + ]) + .unwrap(), + }); + let messages_mimic_calls = data.messages.iter().map(|message| MimicCallInfo { + to: L1_MESSENGER_ADDRESS, + who_to_mimic: KNOWN_CODES_STORAGE_ADDRESS, + data: l1_messenger + .function("sendToL1") + .unwrap() + .encode_input(&[Token::Bytes(message.clone())]) + .unwrap(), + }); + let bytecodes_mimic_calls = data.bytecodes.iter().map(|bytecode| MimicCallInfo { + to: L1_MESSENGER_ADDRESS, + who_to_mimic: KNOWN_CODES_STORAGE_ADDRESS, + data: l1_messenger + .function("requestBytecodeL1Publication") + .unwrap() + .encode_input(&[Token::FixedBytes(hash_bytecode(bytecode).0.to_vec())]) + .unwrap(), + }); + + let encoded_calls = logs_mimic_calls + .chain(messages_mimic_calls) + .chain(bytecodes_mimic_calls) + .map(|call| { + Token::Tuple(vec![ + Token::Address(call.to), + Token::Address(call.who_to_mimic), + Token::Bytes(call.data), + ]) + }) + .collect::>(); + + complex_upgrade + .function("mimicCalls") + .unwrap() + .encode_input(&[Token::Array(encoded_calls)]) + .unwrap() +} + +fn execute_test(test_data: L1MessengerTestData) -> u32 { + let mut storage = get_empty_storage(); + let complex_upgrade_code = read_complex_upgrade(); + + // For this test we'll just put the bytecode onto the force deployer address + storage.borrow_mut().set_value( + get_code_key(&CONTRACT_FORCE_DEPLOYER_ADDRESS), + hash_bytecode(&complex_upgrade_code), + ); + storage + .borrow_mut() + .store_factory_dep(hash_bytecode(&complex_upgrade_code), complex_upgrade_code); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_storage(storage) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let bytecodes = test_data + .bytecodes + .iter() + .map(|bytecode| { + let hash = hash_bytecode(bytecode); + let words = bytes_to_be_words(bytecode.clone()); + (h256_to_u256(hash), words) + }) + .collect(); + vm.vm + .state + .decommittment_processor + .populate(bytecodes, Timestamp(0)); + + let data = populate_mimic_calls(test_data.clone()); + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: CONTRACT_FORCE_DEPLOYER_ADDRESS, + calldata: data, + value: U256::zero(), + factory_deps: None, + }, + None, + ); + + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "Transaction wasn't successful"); + + // Now we count how much ergs were spent at the end of the batch + // It is assumed that the top level frame is the bootloader + + let ergs_before = vm.vm.state.local_state.callstack.current.ergs_remaining; + + // We ensure that indeed the provided state diffs are used + let pubdata_tracer = PubdataTracer::::new_with_forced_state_diffs( + vm.vm.batch_env.clone(), + VmExecutionMode::Batch, + test_data.state_diffs, + ); + + let result = vm.vm.inspect_inner( + TracerDispatcher::default(), + VmExecutionMode::Batch, + Some(pubdata_tracer), + ); + + assert!(!result.result.is_failed(), "Batch wasn't successful"); + + let ergs_after = vm.vm.state.local_state.callstack.current.ergs_remaining; + + ergs_before - ergs_after +} + +fn generate_state_diffs( + repeated_writes: bool, + small_diff: bool, + number_of_state_diffs: usize, +) -> Vec { + (0..number_of_state_diffs) + .map(|i| { + let address = Address::from_low_u64_be(i as u64); + let key = U256::from(i); + let enumeration_index = if repeated_writes { i + 1 } else { 0 }; + + let (initial_value, final_value) = if small_diff { + // As small as it gets, one byte to denote zeroing out the value + (U256::from(1), U256::from(0)) + } else { + // As large as it gets + (U256::from(0), U256::from(2).pow(255.into())) + }; + + StateDiffRecord { + address, + key, + derived_key: u256_to_h256(i.into()).0, + enumeration_index: enumeration_index as u64, + initial_value, + final_value, + } + }) + .collect() +} + +#[test] +fn test_dry_run_upper_bound() { + // We are re-using the `ComplexUpgrade` contract as it already has the `mimicCall` functionality. + // To get the upper bound, we'll try to do the following: + // 1. Max number of logs. + // 2. Lots of small L2->L1 messages / one large L2->L1 message. + // 3. Lots of small bytecodes / one large bytecode. + // 4. Lots of storage slot updates. + + let max_logs = execute_test(L1MessengerTestData { + l2_to_l1_logs: L2ToL1Log::MIN_L2_L1_LOGS_TREE_SIZE, + ..Default::default() + }); + + let max_messages = execute_test(L1MessengerTestData { + // Each L2->L1 message is accompanied by a Log, so the max number of pubdata is bound by it + messages: vec![vec![0; 0]; MAX_PUBDATA_PER_BLOCK as usize / L2ToL1Log::SERIALIZED_SIZE], + ..Default::default() + }); + + let long_message = execute_test(L1MessengerTestData { + // Each L2->L1 message is accompanied by a Log, so the max number of pubdata is bound by it + messages: vec![vec![0; MAX_PUBDATA_PER_BLOCK as usize]; 1], + ..Default::default() + }); + + let max_bytecodes = execute_test(L1MessengerTestData { + // Each bytecode must be at least 32 bytes long + bytecodes: vec![vec![0; 32]; MAX_PUBDATA_PER_BLOCK as usize / 32], + ..Default::default() + }); + + let long_bytecode = execute_test(L1MessengerTestData { + // We have to add 48 since a valid bytecode must have an odd number of 32 byte words + bytecodes: vec![vec![0; MAX_PUBDATA_PER_BLOCK as usize + 48]; 1], + ..Default::default() + }); + + let lots_of_small_repeated_writes = execute_test(L1MessengerTestData { + // In theory each state diff can require only 5 bytes to be published (enum index + 4 bytes for the key) + state_diffs: generate_state_diffs(true, true, MAX_PUBDATA_PER_BLOCK as usize / 5), + ..Default::default() + }); + + let lots_of_big_repeated_writes = execute_test(L1MessengerTestData { + // Each big write will approximately require 32 bytes to encode + state_diffs: generate_state_diffs(true, false, MAX_PUBDATA_PER_BLOCK as usize / 32), + ..Default::default() + }); + + let lots_of_small_initial_writes = execute_test(L1MessengerTestData { + // Each initial write will take at least 32 bytes for derived key + 5 bytes for value + state_diffs: generate_state_diffs(false, true, MAX_PUBDATA_PER_BLOCK as usize / 37), + ..Default::default() + }); + + let lots_of_large_initial_writes = execute_test(L1MessengerTestData { + // Each big write will take at least 32 bytes for derived key + 32 bytes for value + state_diffs: generate_state_diffs(false, false, MAX_PUBDATA_PER_BLOCK as usize / 64), + ..Default::default() + }); + + let max_used_gas = vec![ + max_logs, + max_messages, + long_message, + max_bytecodes, + long_bytecode, + lots_of_small_repeated_writes, + lots_of_big_repeated_writes, + lots_of_small_initial_writes, + lots_of_large_initial_writes, + ] + .into_iter() + .max() + .unwrap(); + + // We use 2x overhead for the batch tip compared to the worst estimated scenario. + assert!( + max_used_gas * 2 <= BOOTLOADER_BATCH_TIP_OVERHEAD, + "BOOTLOADER_BATCH_TIP_OVERHEAD is too low" + ); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/bootloader.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/bootloader.rs new file mode 100644 index 000000000000..f319964efb51 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/bootloader.rs @@ -0,0 +1,56 @@ +use zksync_types::U256; + +use crate::{ + interface::{ExecutionResult, Halt, TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + constants::BOOTLOADER_HEAP_PAGE, + tests::{ + tester::VmTesterBuilder, + utils::{get_bootloader, verify_required_memory, BASE_SYSTEM_CONTRACTS}, + }, + HistoryEnabled, + }, +}; + +#[test] +fn test_dummy_bootloader() { + let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); + base_system_contracts.bootloader = get_bootloader("dummy"); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(base_system_contracts) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let result = vm.vm.execute(VmExecutionMode::Batch); + assert!(!result.result.is_failed()); + + let correct_first_cell = U256::from_str_radix("123123123", 16).unwrap(); + verify_required_memory( + &vm.vm.state, + vec![(correct_first_cell, BOOTLOADER_HEAP_PAGE, 0)], + ); +} + +#[test] +fn test_bootloader_out_of_gas() { + let mut base_system_contracts = BASE_SYSTEM_CONTRACTS.clone(); + base_system_contracts.bootloader = get_bootloader("dummy"); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(base_system_contracts) + .with_gas_limit(10) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let res = vm.vm.execute(VmExecutionMode::Batch); + + assert!(matches!( + res.result, + ExecutionResult::Halt { + reason: Halt::BootloaderOutOfGas + } + )); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/bytecode_publishing.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/bytecode_publishing.rs new file mode 100644 index 000000000000..9db5e7326e71 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/bytecode_publishing.rs @@ -0,0 +1,43 @@ +use zksync_types::event::extract_long_l2_to_l1_messages; +use zksync_utils::bytecode::compress_bytecode; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::{ + tester::{DeployContractsTx, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + HistoryEnabled, + }, +}; + +#[test] +fn test_bytecode_publishing() { + // In this test, we aim to ensure that the contents of the compressed bytecodes + // are included as part of the L2->L1 long messages + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let counter = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + + let compressed_bytecode = compress_bytecode(&counter).unwrap(); + + let DeployContractsTx { tx, .. } = account.get_deploy_tx(&counter, None, TxType::L2); + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "Transaction wasn't successful"); + + vm.vm.execute(VmExecutionMode::Batch); + + let state = vm.vm.get_current_execution_state(); + let long_messages = extract_long_l2_to_l1_messages(&state.events); + assert!( + long_messages.contains(&compressed_bytecode), + "Bytecode not published" + ); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/call_tracer.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/call_tracer.rs new file mode 100644 index 000000000000..1a4c026a23f4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/call_tracer.rs @@ -0,0 +1,92 @@ +use std::sync::Arc; + +use once_cell::sync::OnceCell; +use zksync_types::{Address, Execute}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + tracers::CallTracer, + vm_1_4_1::{ + constants::BLOCK_GAS_LIMIT, + tests::{ + tester::VmTesterBuilder, + utils::{read_max_depth_contract, read_test_contract}, + }, + HistoryEnabled, ToTracerPointer, + }, +}; + +// This test is ultra slow, so it's ignored by default. +#[test] +#[ignore] +fn test_max_depth() { + let contarct = read_max_depth_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contarct, address, true)]) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: vec![], + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let result = Arc::new(OnceCell::new()); + let call_tracer = CallTracer::new(result.clone()).into_tracer_pointer(); + vm.vm.push_transaction(tx); + let res = vm.vm.inspect(call_tracer.into(), VmExecutionMode::OneTx); + assert!(result.get().is_some()); + assert!(res.result.is_failed()); +} + +#[test] +fn test_basic_behavior() { + let contarct = read_test_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contarct, address, true)]) + .build(); + + let increment_by_6_calldata = + "7cf5dab00000000000000000000000000000000000000000000000000000000000000006"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(increment_by_6_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let result = Arc::new(OnceCell::new()); + let call_tracer = CallTracer::new(result.clone()).into_tracer_pointer(); + vm.vm.push_transaction(tx); + let res = vm.vm.inspect(call_tracer.into(), VmExecutionMode::OneTx); + + let call_tracer_result = result.get().unwrap(); + + assert_eq!(call_tracer_result.len(), 1); + // Expect that there are a plenty of subcalls underneath. + let subcall = &call_tracer_result[0].calls; + assert!(subcall.len() > 10); + assert!(!res.result.is_failed()); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/circuits.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/circuits.rs new file mode 100644 index 000000000000..ecc2fdfe6c0a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/circuits.rs @@ -0,0 +1,69 @@ +use zksync_types::{Address, Execute, U256}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{constants::BLOCK_GAS_LIMIT, tests::tester::VmTesterBuilder, HistoryEnabled}, +}; + +// Checks that estimated number of circuits for simple transfer doesn't differ much +// from hardcoded expected value. +#[test] +fn test_circuits() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: Address::random(), + calldata: Vec::new(), + value: U256::from(1u8), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let res = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let s = res.statistics.circuit_statistic; + // Check `circuit_statistic`. + const EXPECTED: [f32; 11] = [ + 1.1979, 0.1390, 1.5455, 0.0031, 1.0573, 0.00059, 0.00226, 0.00077, 0.1195, 0.1429, 0.0, + ]; + let actual = [ + (s.main_vm, "main_vm"), + (s.ram_permutation, "ram_permutation"), + (s.storage_application, "storage_application"), + (s.storage_sorter, "storage_sorter"), + (s.code_decommitter, "code_decommitter"), + (s.code_decommitter_sorter, "code_decommitter_sorter"), + (s.log_demuxer, "log_demuxer"), + (s.events_sorter, "events_sorter"), + (s.keccak256, "keccak256"), + (s.ecrecover, "ecrecover"), + (s.sha256, "sha256"), + ]; + for ((actual, name), expected) in actual.iter().zip(EXPECTED) { + if expected == 0.0 { + assert_eq!( + *actual, expected, + "Check failed for {}, expected {}, actual {}", + name, expected, actual + ); + } else { + let diff = (actual - expected) / expected; + assert!( + diff.abs() < 0.1, + "Check failed for {}, expected {}, actual {}", + name, + expected, + actual + ); + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/default_aa.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/default_aa.rs new file mode 100644 index 000000000000..be8e253c6d8a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/default_aa.rs @@ -0,0 +1,78 @@ +use zksync_system_constants::L2_ETH_TOKEN_ADDRESS; +use zksync_types::{ + get_code_key, get_known_code_key, get_nonce_key, + system_contracts::{DEPLOYMENT_NONCE_INCREMENT, TX_NONCE_INCREMENT}, + AccountTreeId, U256, +}; +use zksync_utils::u256_to_h256; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::{ + tester::{DeployContractsTx, TxType, VmTesterBuilder}, + utils::{get_balance, read_test_contract, verify_required_storage}, + }, + utils::fee::get_batch_base_fee, + HistoryEnabled, + }, +}; + +#[test] +fn test_default_aa_interaction() { + // In this test, we aim to test whether a simple account interaction (without any fee logic) + // will work. The account will try to deploy a simple contract from integration tests. + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let counter = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + let DeployContractsTx { + tx, + bytecode_hash, + address, + } = account.get_deploy_tx(&counter, None, TxType::L2); + let maximal_fee = tx.gas_limit() * get_batch_base_fee(&vm.vm.batch_env); + + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "Transaction wasn't successful"); + + vm.vm.execute(VmExecutionMode::Batch); + vm.vm.get_current_execution_state(); + + // Both deployment and ordinary nonce should be incremented by one. + let account_nonce_key = get_nonce_key(&account.address); + let expected_nonce = TX_NONCE_INCREMENT + DEPLOYMENT_NONCE_INCREMENT; + + // The code hash of the deployed contract should be marked as republished. + let known_codes_key = get_known_code_key(&bytecode_hash); + + // The contract should be deployed successfully. + let account_code_key = get_code_key(&address); + + let expected_slots = vec![ + (u256_to_h256(expected_nonce), account_nonce_key), + (u256_to_h256(U256::from(1u32)), known_codes_key), + (bytecode_hash, account_code_key), + ]; + + verify_required_storage(&vm.vm.state, expected_slots); + + let expected_fee = maximal_fee + - U256::from(result.refunds.gas_refunded) + * U256::from(get_batch_base_fee(&vm.vm.batch_env)); + let operator_balance = get_balance( + AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), + &vm.fee_account, + vm.vm.state.storage.storage.get_ptr(), + ); + + assert_eq!( + operator_balance, expected_fee, + "Operator did not receive his fee" + ); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs new file mode 100644 index 000000000000..0ec921450daf --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/gas_limit.rs @@ -0,0 +1,47 @@ +use zksync_types::{fee::Fee, Execute}; + +use crate::{ + interface::{TxExecutionMode, VmInterface}, + vm_1_4_1::{ + constants::{BOOTLOADER_HEAP_PAGE, TX_DESCRIPTION_OFFSET, TX_GAS_LIMIT_OFFSET}, + tests::tester::VmTesterBuilder, + HistoryDisabled, + }, +}; + +/// Checks that `TX_GAS_LIMIT_OFFSET` constant is correct. +#[test] +fn test_tx_gas_limit_offset() { + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let gas_limit = 9999.into(); + let tx = vm.rich_accounts[0].get_l2_tx_for_execute( + Execute { + contract_address: Default::default(), + calldata: vec![], + value: Default::default(), + factory_deps: None, + }, + Some(Fee { + gas_limit, + ..Default::default() + }), + ); + + vm.vm.push_transaction(tx); + + let gas_limit_from_memory = vm + .vm + .state + .memory + .read_slot( + BOOTLOADER_HEAP_PAGE as usize, + TX_DESCRIPTION_OFFSET + TX_GAS_LIMIT_OFFSET, + ) + .value; + assert_eq!(gas_limit_from_memory, gas_limit); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs new file mode 100644 index 000000000000..ab52ac4e1db3 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/get_used_contracts.rs @@ -0,0 +1,109 @@ +use std::collections::{HashMap, HashSet}; + +use itertools::Itertools; +use zksync_state::WriteStorage; +use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; +use zksync_test_account::Account; +use zksync_types::{Execute, U256}; +use zksync_utils::{bytecode::hash_bytecode, h256_to_u256}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::{ + tester::{TxType, VmTesterBuilder}, + utils::{read_test_contract, BASE_SYSTEM_CONTRACTS}, + }, + HistoryDisabled, Vm, + }, + HistoryMode, +}; + +#[test] +fn test_get_used_contracts() { + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + assert!(known_bytecodes_without_aa_code(&vm.vm).is_empty()); + + // create and push and execute some not-empty factory deps transaction with success status + // to check that `get_used_contracts()` updates + let contract_code = read_test_contract(); + let mut account = Account::random(); + let tx = account.get_deploy_tx(&contract_code, None, TxType::L1 { serial_id: 0 }); + vm.vm.push_transaction(tx.tx.clone()); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); + + assert!(vm + .vm + .get_used_contracts() + .contains(&h256_to_u256(tx.bytecode_hash))); + + // Note: `Default_AA` will be in the list of used contracts if L2 tx is used + assert_eq!( + vm.vm + .get_used_contracts() + .into_iter() + .collect::>(), + known_bytecodes_without_aa_code(&vm.vm) + .keys() + .cloned() + .collect::>() + ); + + // create push and execute some non-empty factory deps transaction that fails + // (`known_bytecodes` will be updated but we expect `get_used_contracts()` to not be updated) + + let calldata = [1, 2, 3]; + let big_calldata: Vec = calldata + .iter() + .cycle() + .take(calldata.len() * 1024) + .cloned() + .collect(); + let account2 = Account::random(); + let tx2 = account2.get_l1_tx( + Execute { + contract_address: CONTRACT_DEPLOYER_ADDRESS, + calldata: big_calldata, + value: Default::default(), + factory_deps: Some(vec![vec![1; 32]]), + }, + 1, + ); + + vm.vm.push_transaction(tx2.clone()); + + let res2 = vm.vm.execute(VmExecutionMode::OneTx); + + assert!(res2.result.is_failed()); + + for factory_dep in tx2.execute.factory_deps.unwrap() { + let hash = hash_bytecode(&factory_dep); + let hash_to_u256 = h256_to_u256(hash); + assert!(known_bytecodes_without_aa_code(&vm.vm) + .keys() + .contains(&hash_to_u256)); + assert!(!vm.vm.get_used_contracts().contains(&hash_to_u256)); + } +} + +fn known_bytecodes_without_aa_code( + vm: &Vm, +) -> HashMap> { + let mut known_bytecodes_without_aa_code = vm + .state + .decommittment_processor + .known_bytecodes + .inner() + .clone(); + + known_bytecodes_without_aa_code + .remove(&h256_to_u256(BASE_SYSTEM_CONTRACTS.default_aa.hash)) + .unwrap(); + + known_bytecodes_without_aa_code +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/invalid_bytecode.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/invalid_bytecode.rs new file mode 100644 index 000000000000..75517138db30 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/invalid_bytecode.rs @@ -0,0 +1,120 @@ +use zksync_types::H256; +use zksync_utils::h256_to_u256; + +use crate::vm_1_4_1::tests::tester::VmTesterBuilder; +use crate::vm_1_4_1::types::inputs::system_env::TxExecutionMode; +use crate::vm_1_4_1::{HistoryEnabled, TxRevertReason}; + +// TODO this test requires a lot of hacks for bypassing the bytecode checks in the VM. +// Port it later, it's not significant. for now + +#[test] +fn test_invalid_bytecode() { + let mut vm_builder = VmTesterBuilder::new(HistoryEnabled) + .with_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1); + let mut storage = vm_builder.take_storage(); + let mut vm = vm_builder.build(&mut storage); + + let block_gas_per_pubdata = vm_test_env + .block_context + .context + .block_gas_price_per_pubdata(); + + let mut test_vm_with_custom_bytecode_hash = + |bytecode_hash: H256, expected_revert_reason: Option| { + let mut oracle_tools = + OracleTools::new(vm_test_env.storage_ptr.as_mut(), HistoryEnabled); + + let (encoded_tx, predefined_overhead) = get_l1_tx_with_custom_bytecode_hash( + h256_to_u256(bytecode_hash), + block_gas_per_pubdata as u32, + ); + + run_vm_with_custom_factory_deps( + &mut oracle_tools, + vm_test_env.block_context.context, + &vm_test_env.block_properties, + encoded_tx, + predefined_overhead, + expected_revert_reason, + ); + }; + + let failed_to_mark_factory_deps = |msg: &str, data: Vec| { + TxRevertReason::FailedToMarkFactoryDependencies(VmRevertReason::General { + msg: msg.to_string(), + data, + }) + }; + + // Here we provide the correctly-formatted bytecode hash of + // odd length, so it should work. + test_vm_with_custom_bytecode_hash( + H256([ + 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]), + None, + ); + + // Here we provide correctly formatted bytecode of even length, so + // it should fail. + test_vm_with_custom_bytecode_hash( + H256([ + 1, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]), + Some(failed_to_mark_factory_deps( + "Code length in words must be odd", + vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 67, 111, 100, 101, 32, 108, 101, 110, + 103, 116, 104, 32, 105, 110, 32, 119, 111, 114, 100, 115, 32, 109, 117, 115, 116, + 32, 98, 101, 32, 111, 100, 100, + ], + )), + ); + + // Here we provide incorrectly formatted bytecode of odd length, so + // it should fail. + test_vm_with_custom_bytecode_hash( + H256([ + 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]), + Some(failed_to_mark_factory_deps( + "Incorrectly formatted bytecodeHash", + vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 73, 110, 99, 111, 114, 114, 101, 99, + 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, + 101, 99, 111, 100, 101, 72, 97, 115, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + )), + ); + + // Here we provide incorrectly formatted bytecode of odd length, so + // it should fail. + test_vm_with_custom_bytecode_hash( + H256([ + 2, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]), + Some(failed_to_mark_factory_deps( + "Incorrectly formatted bytecodeHash", + vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 73, 110, 99, 111, 114, 114, 101, 99, + 116, 108, 121, 32, 102, 111, 114, 109, 97, 116, 116, 101, 100, 32, 98, 121, 116, + 101, 99, 111, 100, 101, 72, 97, 115, 104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + )), + ); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/is_write_initial.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/is_write_initial.rs new file mode 100644 index 000000000000..fd5813bdf949 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/is_write_initial.rs @@ -0,0 +1,48 @@ +use zksync_state::ReadStorage; +use zksync_types::get_nonce_key; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::{ + tester::{Account, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + HistoryDisabled, + }, +}; + +#[test] +fn test_is_write_initial_behaviour() { + // In this test, we check result of `is_write_initial` at different stages. + // The main idea is to check that `is_write_initial` storage uses the correct cache for initial_writes and doesn't + // messed up it with the repeated writes during the one batch execution. + + let mut account = Account::random(); + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let nonce_key = get_nonce_key(&account.address); + // Check that the next write to the nonce key will be initial. + assert!(vm + .storage + .as_ref() + .borrow_mut() + .is_write_initial(&nonce_key)); + + let contract_code = read_test_contract(); + let tx = account.get_deploy_tx(&contract_code, None, TxType::L2).tx; + + vm.vm.push_transaction(tx); + vm.vm.execute(VmExecutionMode::OneTx); + + // Check that `is_write_initial` still returns true for the nonce key. + assert!(vm + .storage + .as_ref() + .borrow_mut() + .is_write_initial(&nonce_key)); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/l1_tx_execution.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/l1_tx_execution.rs new file mode 100644 index 000000000000..e98fc23c6eb4 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/l1_tx_execution.rs @@ -0,0 +1,189 @@ +use ethabi::Token; +use zksync_contracts::l1_messenger_contract; +use zksync_system_constants::{BOOTLOADER_ADDRESS, L1_MESSENGER_ADDRESS}; +use zksync_types::{ + get_code_key, get_known_code_key, + l2_to_l1_log::{L2ToL1Log, UserL2ToL1Log}, + storage_writes_deduplicator::StorageWritesDeduplicator, + Execute, ExecuteTransactionCommon, U256, +}; +use zksync_utils::u256_to_h256; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::{ + tester::{TxType, VmTesterBuilder}, + utils::{read_test_contract, verify_required_storage, BASE_SYSTEM_CONTRACTS}, + }, + types::internals::TransactionData, + HistoryEnabled, + }, +}; + +#[test] +fn test_l1_tx_execution() { + // In this test, we try to execute a contract deployment from L1 + // Here instead of marking code hash via the bootloader means, we will be + // using L1->L2 communication, the same it would likely be done during the priority mode. + + // There are always at least 7 initial writes here, because we pay fees from l1: + // - `totalSupply` of ETH token + // - balance of the refund recipient + // - balance of the bootloader + // - `tx_rolling` hash + // - rolling hash of L2->L1 logs + // - transaction number in block counter + // - L2->L1 log counter in `L1Messenger` + + // TODO(PLA-537): right now we are using 4 slots instead of 7 due to 0 fee for transaction. + let basic_initial_writes = 4; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(BASE_SYSTEM_CONTRACTS.clone()) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let contract_code = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + let deploy_tx = account.get_deploy_tx(&contract_code, None, TxType::L1 { serial_id: 1 }); + let tx_data: TransactionData = deploy_tx.tx.clone().into(); + + let required_l2_to_l1_logs: Vec<_> = vec![L2ToL1Log { + shard_id: 0, + is_service: true, + tx_number_in_block: 0, + sender: BOOTLOADER_ADDRESS, + key: tx_data.tx_hash(0.into()), + value: u256_to_h256(U256::from(1u32)), + }] + .into_iter() + .map(UserL2ToL1Log) + .collect(); + + vm.vm.push_transaction(deploy_tx.tx.clone()); + + let res = vm.vm.execute(VmExecutionMode::OneTx); + + // The code hash of the deployed contract should be marked as republished. + let known_codes_key = get_known_code_key(&deploy_tx.bytecode_hash); + + // The contract should be deployed successfully. + let account_code_key = get_code_key(&deploy_tx.address); + + let expected_slots = vec![ + (u256_to_h256(U256::from(1u32)), known_codes_key), + (deploy_tx.bytecode_hash, account_code_key), + ]; + assert!(!res.result.is_failed()); + + verify_required_storage(&vm.vm.state, expected_slots); + + assert_eq!(res.logs.user_l2_to_l1_logs, required_l2_to_l1_logs); + + let tx = account.get_test_contract_transaction( + deploy_tx.address, + true, + None, + false, + TxType::L1 { serial_id: 0 }, + ); + vm.vm.push_transaction(tx); + let res = vm.vm.execute(VmExecutionMode::OneTx); + let storage_logs = res.logs.storage_logs; + let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); + + // Tx panicked + assert_eq!(res.initial_storage_writes - basic_initial_writes, 0); + + let tx = account.get_test_contract_transaction( + deploy_tx.address, + false, + None, + false, + TxType::L1 { serial_id: 0 }, + ); + vm.vm.push_transaction(tx.clone()); + let res = vm.vm.execute(VmExecutionMode::OneTx); + let storage_logs = res.logs.storage_logs; + let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); + // We changed one slot inside contract + assert_eq!(res.initial_storage_writes - basic_initial_writes, 1); + + // No repeated writes + let repeated_writes = res.repeated_storage_writes; + assert_eq!(res.repeated_storage_writes, 0); + + vm.vm.push_transaction(tx); + let storage_logs = vm.vm.execute(VmExecutionMode::OneTx).logs.storage_logs; + let res = StorageWritesDeduplicator::apply_on_empty_state(&storage_logs); + // We do the same storage write, it will be deduplicated, so still 4 initial write and 0 repeated + assert_eq!(res.initial_storage_writes - basic_initial_writes, 1); + assert_eq!(res.repeated_storage_writes, repeated_writes); + + let tx = account.get_test_contract_transaction( + deploy_tx.address, + false, + Some(10.into()), + false, + TxType::L1 { serial_id: 1 }, + ); + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + // Method is not payable tx should fail + assert!(result.result.is_failed(), "The transaction should fail"); + + let res = StorageWritesDeduplicator::apply_on_empty_state(&result.logs.storage_logs); + // There are only basic initial writes + assert_eq!(res.initial_storage_writes - basic_initial_writes, 2); +} + +#[test] +fn test_l1_tx_execution_high_gas_limit() { + // In this test, we try to execute an L1->L2 transaction with a high gas limit. + // Usually priority transactions with dangerously gas limit should even pass the checks on the L1, + // however, they might pass during the transition period to the new fee model, so we check that we can safely process those. + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(BASE_SYSTEM_CONTRACTS.clone()) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let account = &mut vm.rich_accounts[0]; + + let l1_messenger = l1_messenger_contract(); + + let contract_function = l1_messenger.function("sendToL1").unwrap(); + let params = [ + // Even a message of size 100k should not be able to be sent by a priority transaction + Token::Bytes(vec![0u8; 100_000]), + ]; + let calldata = contract_function.encode_input(¶ms).unwrap(); + + let mut tx = account.get_l1_tx( + Execute { + contract_address: L1_MESSENGER_ADDRESS, + value: 0.into(), + factory_deps: None, + calldata, + }, + 0, + ); + + if let ExecuteTransactionCommon::L1(data) = &mut tx.common_data { + // Using some large gas limit + data.gas_limit = 300_000_000.into(); + } else { + unreachable!() + }; + + vm.vm.push_transaction(tx); + + let res = vm.vm.execute(VmExecutionMode::OneTx); + + assert!(res.result.is_failed(), "The transaction should've failed"); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/l2_blocks.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/l2_blocks.rs new file mode 100644 index 000000000000..0aaa1e6a6c5e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/l2_blocks.rs @@ -0,0 +1,437 @@ +//! +//! Tests for the bootloader +//! The description for each of the tests can be found in the corresponding `.yul` file. +//! + +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_state::WriteStorage; +use zksync_system_constants::REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE; +use zksync_types::{ + block::{pack_block_info, MiniblockHasher}, + AccountTreeId, Execute, ExecuteTransactionCommon, L1BatchNumber, L1TxCommonData, + MiniblockNumber, ProtocolVersionId, StorageKey, Transaction, H160, H256, + SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_BLOCK_INFO_POSITION, + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + U256, +}; +use zksync_utils::{h256_to_u256, u256_to_h256}; + +use crate::{ + interface::{ExecutionResult, Halt, L2BlockEnv, TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + constants::{ + BOOTLOADER_HEAP_PAGE, TX_OPERATOR_L2_BLOCK_INFO_OFFSET, + TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO, + }, + tests::tester::{default_l1_batch, VmTesterBuilder}, + utils::l2_blocks::get_l2_block_hash_key, + HistoryEnabled, Vm, + }, + HistoryMode, +}; + +fn get_l1_noop() -> Transaction { + Transaction { + common_data: ExecuteTransactionCommon::L1(L1TxCommonData { + sender: H160::random(), + gas_limit: U256::from(2000000u32), + gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), + ..Default::default() + }), + execute: Execute { + contract_address: H160::zero(), + calldata: vec![], + value: U256::zero(), + factory_deps: None, + }, + received_timestamp_ms: 0, + raw_bytes: None, + } +} + +#[test] +fn test_l2_block_initialization_timestamp() { + // This test checks that the L2 block initialization works correctly. + // Here we check that that the first block must have timestamp that is greater or equal to the timestamp + // of the current batch. + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + // Override the timestamp of the current miniblock to be 0. + vm.vm.bootloader_state.push_l2_block(L2BlockEnv { + number: 1, + timestamp: 0, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 1, + }); + let l1_tx = get_l1_noop(); + + vm.vm.push_transaction(l1_tx); + let res = vm.vm.execute(VmExecutionMode::OneTx); + + assert_eq!( + res.result, + ExecutionResult::Halt {reason: Halt::FailedToSetL2Block("The timestamp of the L2 block must be greater than or equal to the timestamp of the current batch".to_string())} + ); +} + +#[test] +fn test_l2_block_initialization_number_non_zero() { + // This test checks that the L2 block initialization works correctly. + // Here we check that the first miniblock number can not be zero. + + let l1_batch = default_l1_batch(L1BatchNumber(1)); + let first_l2_block = L2BlockEnv { + number: 0, + timestamp: l1_batch.timestamp, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 1, + }; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_l1_batch_env(l1_batch) + .with_random_rich_accounts(1) + .build(); + + let l1_tx = get_l1_noop(); + + vm.vm.push_transaction(l1_tx); + + let timestamp = Timestamp(vm.vm.state.local_state.timestamp); + set_manual_l2_block_info(&mut vm.vm, 0, first_l2_block, timestamp); + + let res = vm.vm.execute(VmExecutionMode::OneTx); + + assert_eq!( + res.result, + ExecutionResult::Halt { + reason: Halt::FailedToSetL2Block( + "L2 block number is never expected to be zero".to_string() + ) + } + ); +} + +fn test_same_l2_block( + expected_error: Option, + override_timestamp: Option, + override_prev_block_hash: Option, +) { + let mut l1_batch = default_l1_batch(L1BatchNumber(1)); + l1_batch.timestamp = 1; + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_l1_batch_env(l1_batch) + .with_random_rich_accounts(1) + .build(); + + let l1_tx = get_l1_noop(); + vm.vm.push_transaction(l1_tx.clone()); + let res = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!res.result.is_failed()); + + let mut current_l2_block = vm.vm.batch_env.first_l2_block; + + if let Some(timestamp) = override_timestamp { + current_l2_block.timestamp = timestamp; + } + if let Some(prev_block_hash) = override_prev_block_hash { + current_l2_block.prev_block_hash = prev_block_hash; + } + + if (None, None) == (override_timestamp, override_prev_block_hash) { + current_l2_block.max_virtual_blocks_to_create = 0; + } + + vm.vm.push_transaction(l1_tx); + let timestamp = Timestamp(vm.vm.state.local_state.timestamp); + set_manual_l2_block_info(&mut vm.vm, 1, current_l2_block, timestamp); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + + if let Some(err) = expected_error { + assert_eq!(result.result, ExecutionResult::Halt { reason: err }); + } else { + assert_eq!(result.result, ExecutionResult::Success { output: vec![] }); + } +} + +#[test] +fn test_l2_block_same_l2_block() { + // This test aims to test the case when there are multiple transactions inside the same L2 block. + + // Case 1: Incorrect timestamp + test_same_l2_block( + Some(Halt::FailedToSetL2Block( + "The timestamp of the same L2 block must be same".to_string(), + )), + Some(0), + None, + ); + + // Case 2: Incorrect previous block hash + test_same_l2_block( + Some(Halt::FailedToSetL2Block( + "The previous hash of the same L2 block must be same".to_string(), + )), + None, + Some(H256::zero()), + ); + + // Case 3: Correct continuation of the same L2 block + test_same_l2_block(None, None, None); +} + +fn test_new_l2_block( + first_l2_block: L2BlockEnv, + overriden_second_block_number: Option, + overriden_second_block_timestamp: Option, + overriden_second_block_prev_block_hash: Option, + expected_error: Option, +) { + let mut l1_batch = default_l1_batch(L1BatchNumber(1)); + l1_batch.timestamp = 1; + l1_batch.first_l2_block = first_l2_block; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let l1_tx = get_l1_noop(); + + // Firstly we execute the first transaction + vm.vm.push_transaction(l1_tx.clone()); + vm.vm.execute(VmExecutionMode::OneTx); + + let mut second_l2_block = vm.vm.batch_env.first_l2_block; + second_l2_block.number += 1; + second_l2_block.timestamp += 1; + second_l2_block.prev_block_hash = vm.vm.bootloader_state.last_l2_block().get_hash(); + + if let Some(block_number) = overriden_second_block_number { + second_l2_block.number = block_number; + } + if let Some(timestamp) = overriden_second_block_timestamp { + second_l2_block.timestamp = timestamp; + } + if let Some(prev_block_hash) = overriden_second_block_prev_block_hash { + second_l2_block.prev_block_hash = prev_block_hash; + } + + vm.vm.bootloader_state.push_l2_block(second_l2_block); + + vm.vm.push_transaction(l1_tx); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + if let Some(err) = expected_error { + assert_eq!(result.result, ExecutionResult::Halt { reason: err }); + } else { + assert_eq!(result.result, ExecutionResult::Success { output: vec![] }); + } +} + +#[test] +fn test_l2_block_new_l2_block() { + // This test is aimed to cover potential issue + + let correct_first_block = L2BlockEnv { + number: 1, + timestamp: 1, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 1, + }; + + // Case 1: Block number increasing by more than 1 + test_new_l2_block( + correct_first_block, + Some(3), + None, + None, + Some(Halt::FailedToSetL2Block( + "Invalid new L2 block number".to_string(), + )), + ); + + // Case 2: Timestamp not increasing + test_new_l2_block( + correct_first_block, + None, + Some(1), + None, + Some(Halt::FailedToSetL2Block("The timestamp of the new L2 block must be greater than the timestamp of the previous L2 block".to_string())), + ); + + // Case 3: Incorrect previous block hash + test_new_l2_block( + correct_first_block, + None, + None, + Some(H256::zero()), + Some(Halt::FailedToSetL2Block( + "The current L2 block hash is incorrect".to_string(), + )), + ); + + // Case 4: Correct new block + test_new_l2_block(correct_first_block, None, None, None, None); +} + +#[allow(clippy::too_many_arguments)] +fn test_first_in_batch( + miniblock_timestamp: u64, + miniblock_number: u32, + pending_txs_hash: H256, + batch_timestamp: u64, + new_batch_timestamp: u64, + batch_number: u32, + proposed_block: L2BlockEnv, + expected_error: Option, +) { + let mut l1_batch = default_l1_batch(L1BatchNumber(1)); + l1_batch.number += 1; + l1_batch.timestamp = new_batch_timestamp; + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + let l1_tx = get_l1_noop(); + + // Setting the values provided. + let storage_ptr = vm.vm.state.storage.storage.get_ptr(); + let miniblock_info_slot = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, + ); + let pending_txs_hash_slot = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + ); + let batch_info_slot = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_BLOCK_INFO_POSITION, + ); + let prev_block_hash_position = get_l2_block_hash_key(miniblock_number - 1); + + storage_ptr.borrow_mut().set_value( + miniblock_info_slot, + u256_to_h256(pack_block_info( + miniblock_number as u64, + miniblock_timestamp, + )), + ); + storage_ptr + .borrow_mut() + .set_value(pending_txs_hash_slot, pending_txs_hash); + storage_ptr.borrow_mut().set_value( + batch_info_slot, + u256_to_h256(pack_block_info(batch_number as u64, batch_timestamp)), + ); + storage_ptr.borrow_mut().set_value( + prev_block_hash_position, + MiniblockHasher::legacy_hash(MiniblockNumber(miniblock_number - 1)), + ); + + // In order to skip checks from the Rust side of the VM, we firstly use some definitely correct L2 block info. + // And then override it with the user-provided value + + let last_l2_block = vm.vm.bootloader_state.last_l2_block(); + let new_l2_block = L2BlockEnv { + number: last_l2_block.number + 1, + timestamp: last_l2_block.timestamp + 1, + prev_block_hash: last_l2_block.get_hash(), + max_virtual_blocks_to_create: last_l2_block.max_virtual_blocks_to_create, + }; + + vm.vm.bootloader_state.push_l2_block(new_l2_block); + vm.vm.push_transaction(l1_tx); + let timestamp = Timestamp(vm.vm.state.local_state.timestamp); + set_manual_l2_block_info(&mut vm.vm, 0, proposed_block, timestamp); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + if let Some(err) = expected_error { + assert_eq!(result.result, ExecutionResult::Halt { reason: err }); + } else { + assert_eq!(result.result, ExecutionResult::Success { output: vec![] }); + } +} + +#[test] +fn test_l2_block_first_in_batch() { + let prev_block_hash = MiniblockHasher::legacy_hash(MiniblockNumber(0)); + let prev_block_hash = MiniblockHasher::new(MiniblockNumber(1), 1, prev_block_hash) + .finalize(ProtocolVersionId::latest()); + test_first_in_batch( + 1, + 1, + H256::zero(), + 1, + 2, + 1, + L2BlockEnv { + number: 2, + timestamp: 2, + prev_block_hash, + max_virtual_blocks_to_create: 1, + }, + None, + ); + + let prev_block_hash = MiniblockHasher::legacy_hash(MiniblockNumber(0)); + let prev_block_hash = MiniblockHasher::new(MiniblockNumber(1), 8, prev_block_hash) + .finalize(ProtocolVersionId::latest()); + test_first_in_batch( + 8, + 1, + H256::zero(), + 5, + 12, + 1, + L2BlockEnv { + number: 2, + timestamp: 9, + prev_block_hash, + max_virtual_blocks_to_create: 1, + }, + Some(Halt::FailedToSetL2Block("The timestamp of the L2 block must be greater than or equal to the timestamp of the current batch".to_string())), + ); +} + +fn set_manual_l2_block_info( + vm: &mut Vm, + tx_number: usize, + block_info: L2BlockEnv, + timestamp: Timestamp, +) { + let fictive_miniblock_position = + TX_OPERATOR_L2_BLOCK_INFO_OFFSET + TX_OPERATOR_SLOTS_PER_L2_BLOCK_INFO * tx_number; + + vm.state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + vec![ + (fictive_miniblock_position, block_info.number.into()), + (fictive_miniblock_position + 1, block_info.timestamp.into()), + ( + fictive_miniblock_position + 2, + h256_to_u256(block_info.prev_block_hash), + ), + ( + fictive_miniblock_position + 3, + block_info.max_virtual_blocks_to_create.into(), + ), + ], + timestamp, + ) +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/mod.rs new file mode 100644 index 000000000000..a07608121bc1 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/mod.rs @@ -0,0 +1,23 @@ +mod bootloader; +mod default_aa; +// TODO - fix this test +// `mod invalid_bytecode;` +mod block_tip; +mod bytecode_publishing; +mod call_tracer; +mod circuits; +mod gas_limit; +mod get_used_contracts; +mod is_write_initial; +mod l1_tx_execution; +mod l2_blocks; +mod nonce_holder; +mod precompiles; +mod refunds; +mod require_eip712; +mod rollbacks; +mod simple_execution; +mod tester; +mod tracing_execution_error; +mod upgrade; +mod utils; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/nonce_holder.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/nonce_holder.rs new file mode 100644 index 000000000000..915a802b1e85 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/nonce_holder.rs @@ -0,0 +1,188 @@ +use zksync_types::{Execute, Nonce}; + +use crate::{ + interface::{ + ExecutionResult, Halt, TxExecutionMode, TxRevertReason, VmExecutionMode, VmInterface, + VmRevertReason, + }, + vm_1_4_1::{ + tests::{ + tester::{Account, VmTesterBuilder}, + utils::read_nonce_holder_tester, + }, + types::internals::TransactionData, + HistoryEnabled, + }, +}; + +pub enum NonceHolderTestMode { + SetValueUnderNonce, + IncreaseMinNonceBy5, + IncreaseMinNonceTooMuch, + LeaveNonceUnused, + IncreaseMinNonceBy1, + SwitchToArbitraryOrdering, +} + +impl From for u8 { + fn from(mode: NonceHolderTestMode) -> u8 { + match mode { + NonceHolderTestMode::SetValueUnderNonce => 0, + NonceHolderTestMode::IncreaseMinNonceBy5 => 1, + NonceHolderTestMode::IncreaseMinNonceTooMuch => 2, + NonceHolderTestMode::LeaveNonceUnused => 3, + NonceHolderTestMode::IncreaseMinNonceBy1 => 4, + NonceHolderTestMode::SwitchToArbitraryOrdering => 5, + } + } +} + +#[test] +fn test_nonce_holder() { + let mut account = Account::random(); + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_deployer() + .with_custom_contracts(vec![( + read_nonce_holder_tester().to_vec(), + account.address, + true, + )]) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let mut run_nonce_test = |nonce: u32, + test_mode: NonceHolderTestMode, + error_message: Option, + comment: &'static str| { + // In this test we have to reset VM state after each test case. Because once bootloader failed during the validation of the transaction, + // it will fail again and again. At the same time we have to keep the same storage, because we want to keep the nonce holder contract state. + // The easiest way in terms of lifetimes is to reuse `vm_builder` to achieve it. + vm.reset_state(true); + let mut transaction_data: TransactionData = account + .get_l2_tx_for_execute_with_nonce( + Execute { + contract_address: account.address, + calldata: vec![12], + value: Default::default(), + factory_deps: None, + }, + None, + Nonce(nonce), + ) + .into(); + + transaction_data.signature = vec![test_mode.into()]; + vm.vm.push_raw_transaction(transaction_data, 0, 0, true); + let result = vm.vm.execute(VmExecutionMode::OneTx); + + if let Some(msg) = error_message { + let expected_error = + TxRevertReason::Halt(Halt::ValidationFailed(VmRevertReason::General { + msg, + data: vec![], + })); + let ExecutionResult::Halt { reason } = result.result else { + panic!("Expected revert, got {:?}", result.result); + }; + assert_eq!( + reason.to_string(), + expected_error.to_string(), + "{}", + comment + ); + } else { + assert!(!result.result.is_failed(), "{}", comment); + } + }; + // Test 1: trying to set value under non sequential nonce value. + run_nonce_test( + 1u32, + NonceHolderTestMode::SetValueUnderNonce, + Some("Previous nonce has not been used".to_string()), + "Allowed to set value under non sequential value", + ); + + // Test 2: increase min nonce by 1 with sequential nonce ordering: + run_nonce_test( + 0u32, + NonceHolderTestMode::IncreaseMinNonceBy1, + None, + "Failed to increment nonce by 1 for sequential account", + ); + + // Test 3: correctly set value under nonce with sequential nonce ordering: + run_nonce_test( + 1u32, + NonceHolderTestMode::SetValueUnderNonce, + None, + "Failed to set value under nonce sequential value", + ); + + // Test 5: migrate to the arbitrary nonce ordering: + run_nonce_test( + 2u32, + NonceHolderTestMode::SwitchToArbitraryOrdering, + None, + "Failed to switch to arbitrary ordering", + ); + + // Test 6: increase min nonce by 5 + run_nonce_test( + 6u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + None, + "Failed to increase min nonce by 5", + ); + + // Test 7: since the nonces in range [6,10] are no longer allowed, the + // tx with nonce 10 should not be allowed + run_nonce_test( + 10u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + Some("Reusing the same nonce twice".to_string()), + "Allowed to reuse nonce below the minimal one", + ); + + // Test 8: we should be able to use nonce 13 + run_nonce_test( + 13u32, + NonceHolderTestMode::SetValueUnderNonce, + None, + "Did not allow to use unused nonce 10", + ); + + // Test 9: we should not be able to reuse nonce 13 + run_nonce_test( + 13u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + Some("Reusing the same nonce twice".to_string()), + "Allowed to reuse the same nonce twice", + ); + + // Test 10: we should be able to simply use nonce 14, while bumping the minimal nonce by 5 + run_nonce_test( + 14u32, + NonceHolderTestMode::IncreaseMinNonceBy5, + None, + "Did not allow to use a bumped nonce", + ); + + // Test 11: Do not allow bumping nonce by too much + run_nonce_test( + 16u32, + NonceHolderTestMode::IncreaseMinNonceTooMuch, + Some("The value for incrementing the nonce is too high".to_string()), + "Allowed for incrementing min nonce too much", + ); + + // Test 12: Do not allow not setting a nonce as used + run_nonce_test( + 16u32, + NonceHolderTestMode::LeaveNonceUnused, + Some("The nonce was not set as used".to_string()), + "Allowed to leave nonce as unused", + ); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/precompiles.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/precompiles.rs new file mode 100644 index 000000000000..37e871fbc70e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/precompiles.rs @@ -0,0 +1,136 @@ +use zk_evm_1_4_1::zk_evm_abstractions::precompiles::PrecompileAddress; +use zksync_types::{Address, Execute}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + constants::BLOCK_GAS_LIMIT, + tests::{tester::VmTesterBuilder, utils::read_precompiles_contract}, + HistoryEnabled, + }, +}; + +#[test] +fn test_keccak() { + // Execute special transaction and check that at least 1000 keccak calls were made. + let contract = read_precompiles_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contract, address, true)]) + .build(); + + // calldata for `doKeccak(1000)`. + let keccak1000_calldata = + "370f20ac00000000000000000000000000000000000000000000000000000000000003e8"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(keccak1000_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let keccak_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::Keccak256) + .count(); + + assert!(keccak_count >= 1000); +} + +#[test] +fn test_sha256() { + // Execute special transaction and check that at least 1000 `sha256` calls were made. + let contract = read_precompiles_contract(); + let address = Address::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_custom_contracts(vec![(contract, address, true)]) + .build(); + + // calldata for `doSha256(1000)`. + let sha1000_calldata = + "5d0b4fb500000000000000000000000000000000000000000000000000000000000003e8"; + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: hex::decode(sha1000_calldata).unwrap(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let sha_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::SHA256) + .count(); + + assert!(sha_count >= 1000); +} + +#[test] +fn test_ecrecover() { + // Execute simple transfer and check that exactly 1 `ecrecover` call was made (it's done during tx validation). + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_random_rich_accounts(1) + .with_deployer() + .with_gas_limit(BLOCK_GAS_LIMIT) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .build(); + + let account = &mut vm.rich_accounts[0]; + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address: account.address, + calldata: Vec::new(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + vm.vm.push_transaction(tx); + let _ = vm.vm.inspect(Default::default(), VmExecutionMode::OneTx); + + let ecrecover_count = vm + .vm + .state + .precompiles_processor + .precompile_cycles_history + .inner() + .iter() + .filter(|(precompile, _)| precompile == &PrecompileAddress::Ecrecover) + .count(); + + assert_eq!(ecrecover_count, 1); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/refunds.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/refunds.rs new file mode 100644 index 000000000000..8700eb14b53d --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/refunds.rs @@ -0,0 +1,166 @@ +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::{ + tester::{DeployContractsTx, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + types::internals::TransactionData, + HistoryEnabled, + }, +}; + +#[test] +fn test_predetermined_refunded_gas() { + // In this test, we compare the execution of the bootloader with the predefined + // refunded gas and without them + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + let l1_batch = vm.vm.batch_env.clone(); + + let counter = read_test_contract(); + let account = &mut vm.rich_accounts[0]; + + let DeployContractsTx { + tx, + bytecode_hash: _, + address: _, + } = account.get_deploy_tx(&counter, None, TxType::L2); + vm.vm.push_transaction(tx.clone()); + let result = vm.vm.execute(VmExecutionMode::OneTx); + + assert!(!result.result.is_failed()); + + // If the refund provided by the operator or the final refund are the 0 + // there is no impact of the operator's refund at all and so this test does not + // make much sense. + assert!( + result.refunds.operator_suggested_refund > 0, + "The operator's refund is 0" + ); + assert!(result.refunds.gas_refunded > 0, "The final refund is 0"); + + let result_without_predefined_refunds = vm.vm.execute(VmExecutionMode::Batch); + let mut current_state_without_predefined_refunds = vm.vm.get_current_execution_state(); + assert!(!result_without_predefined_refunds.result.is_failed(),); + + // Here we want to provide the same refund from the operator and check that it's the correct one. + // We execute the whole block without refund tracer, because refund tracer will eventually override the provided refund. + // But the overall result should be the same + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch.clone()) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let tx: TransactionData = tx.into(); + // Overhead + let overhead = tx.overhead_gas(); + vm.vm + .push_raw_transaction(tx.clone(), overhead, result.refunds.gas_refunded, true); + + let result_with_predefined_refunds = vm.vm.execute(VmExecutionMode::Batch); + let mut current_state_with_predefined_refunds = vm.vm.get_current_execution_state(); + + assert!(!result_with_predefined_refunds.result.is_failed()); + + // We need to sort these lists as those are flattened from HashMaps + current_state_with_predefined_refunds + .used_contract_hashes + .sort(); + current_state_without_predefined_refunds + .used_contract_hashes + .sort(); + + assert_eq!( + current_state_with_predefined_refunds.events, + current_state_without_predefined_refunds.events + ); + + assert_eq!( + current_state_with_predefined_refunds.user_l2_to_l1_logs, + current_state_without_predefined_refunds.user_l2_to_l1_logs + ); + + assert_eq!( + current_state_with_predefined_refunds.system_logs, + current_state_without_predefined_refunds.system_logs + ); + + assert_eq!( + current_state_with_predefined_refunds.storage_log_queries, + current_state_without_predefined_refunds.storage_log_queries + ); + assert_eq!( + current_state_with_predefined_refunds.used_contract_hashes, + current_state_without_predefined_refunds.used_contract_hashes + ); + + // In this test we put the different refund from the operator. + // We still can't use the refund tracer, because it will override the refund. + // But we can check that the logs and events have changed. + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_l1_batch_env(l1_batch) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account.clone()]) + .build(); + + let changed_operator_suggested_refund = result.refunds.gas_refunded + 1000; + vm.vm + .push_raw_transaction(tx, overhead, changed_operator_suggested_refund, true); + let result = vm.vm.execute(VmExecutionMode::Batch); + let mut current_state_with_changed_predefined_refunds = vm.vm.get_current_execution_state(); + + assert!(!result.result.is_failed()); + current_state_with_changed_predefined_refunds + .used_contract_hashes + .sort(); + current_state_without_predefined_refunds + .used_contract_hashes + .sort(); + + assert_eq!( + current_state_with_changed_predefined_refunds.events.len(), + current_state_without_predefined_refunds.events.len() + ); + + assert_ne!( + current_state_with_changed_predefined_refunds.events, + current_state_without_predefined_refunds.events + ); + + assert_eq!( + current_state_with_changed_predefined_refunds.user_l2_to_l1_logs, + current_state_without_predefined_refunds.user_l2_to_l1_logs + ); + + assert_ne!( + current_state_with_changed_predefined_refunds.system_logs, + current_state_without_predefined_refunds.system_logs + ); + + assert_eq!( + current_state_with_changed_predefined_refunds + .storage_log_queries + .len(), + current_state_without_predefined_refunds + .storage_log_queries + .len() + ); + + assert_ne!( + current_state_with_changed_predefined_refunds.storage_log_queries, + current_state_without_predefined_refunds.storage_log_queries + ); + assert_eq!( + current_state_with_changed_predefined_refunds.used_contract_hashes, + current_state_without_predefined_refunds.used_contract_hashes + ); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/require_eip712.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/require_eip712.rs new file mode 100644 index 000000000000..aebc956e6735 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/require_eip712.rs @@ -0,0 +1,165 @@ +use std::convert::TryInto; + +use ethabi::Token; +use zksync_eth_signer::{raw_ethereum_tx::TransactionParameters, EthereumSigner}; +use zksync_system_constants::L2_ETH_TOKEN_ADDRESS; +use zksync_types::{ + fee::Fee, l2::L2Tx, transaction_request::TransactionRequest, + utils::storage_key_for_standard_token_balance, AccountTreeId, Address, Eip712Domain, Execute, + L2ChainId, Nonce, Transaction, U256, +}; + +use crate::{ + interface::{TxExecutionMode, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::{ + tester::{Account, VmTester, VmTesterBuilder}, + utils::read_many_owners_custom_account_contract, + }, + HistoryDisabled, + }, +}; + +impl VmTester { + pub(crate) fn get_eth_balance(&mut self, address: Address) -> U256 { + let key = storage_key_for_standard_token_balance( + AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), + &address, + ); + self.vm.state.storage.storage.read_from_storage(&key) + } +} + +// TODO refactor this test it use too much internal details of the VM +#[tokio::test] +/// This test deploys 'buggy' account abstraction code, and then tries accessing it both with legacy +/// and EIP712 transactions. +/// Currently we support both, but in the future, we should allow only EIP712 transactions to access the AA accounts. +async fn test_require_eip712() { + // Use 3 accounts: + // - `private_address` - EOA account, where we have the key + // - `account_address` - AA account, where the contract is deployed + // - beneficiary - an EOA account, where we'll try to transfer the tokens. + let account_abstraction = Account::random(); + let mut private_account = Account::random(); + let beneficiary = Account::random(); + + let (bytecode, contract) = read_many_owners_custom_account_contract(); + let mut vm = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_custom_contracts(vec![(bytecode, account_abstraction.address, true)]) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_rich_accounts(vec![account_abstraction.clone(), private_account.clone()]) + .build(); + + assert_eq!(vm.get_eth_balance(beneficiary.address), U256::from(0)); + + let chain_id: u32 = 270; + + // First, let's set the owners of the AA account to the `private_address`. + // (so that messages signed by `private_address`, are authorized to act on behalf of the AA account). + let set_owners_function = contract.function("setOwners").unwrap(); + let encoded_input = set_owners_function + .encode_input(&[Token::Array(vec![Token::Address(private_account.address)])]) + .unwrap(); + + let tx = private_account.get_l2_tx_for_execute( + Execute { + contract_address: account_abstraction.address, + calldata: encoded_input, + value: Default::default(), + factory_deps: None, + }, + None, + ); + + vm.vm.push_transaction(tx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); + + let private_account_balance = vm.get_eth_balance(private_account.address); + + // And now let's do the transfer from the 'account abstraction' to 'beneficiary' (using 'legacy' transaction). + // Normally this would not work - unless the operator is malicious. + let aa_raw_tx = TransactionParameters { + nonce: U256::from(0), + to: Some(beneficiary.address), + gas: U256::from(100000000), + gas_price: Some(U256::from(10000000)), + value: U256::from(888000088), + data: vec![], + chain_id: 270, + transaction_type: None, + access_list: None, + max_fee_per_gas: U256::from(1000000000), + max_priority_fee_per_gas: U256::from(1000000000), + }; + + let aa_tx = private_account.sign_legacy_tx(aa_raw_tx).await; + let (tx_request, hash) = TransactionRequest::from_bytes(&aa_tx, L2ChainId::from(270)).unwrap(); + + let mut l2_tx: L2Tx = L2Tx::from_request(tx_request, 10000).unwrap(); + l2_tx.set_input(aa_tx, hash); + // Pretend that operator is malicious and sets the initiator to the AA account. + l2_tx.common_data.initiator_address = account_abstraction.address; + let transaction: Transaction = l2_tx.try_into().unwrap(); + + vm.vm.push_transaction(transaction); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); + assert_eq!( + vm.get_eth_balance(beneficiary.address), + U256::from(888000088) + ); + // Make sure that the tokens were transferred from the AA account. + assert_eq!( + private_account_balance, + vm.get_eth_balance(private_account.address) + ); + + // // Now send the 'classic' EIP712 transaction + let tx_712 = L2Tx::new( + beneficiary.address, + vec![], + Nonce(1), + Fee { + gas_limit: U256::from(1000000000), + max_fee_per_gas: U256::from(1000000000), + max_priority_fee_per_gas: U256::from(1000000000), + gas_per_pubdata_limit: U256::from(1000000000), + }, + account_abstraction.address, + U256::from(28374938), + None, + Default::default(), + ); + + let transaction_request: TransactionRequest = tx_712.into(); + + let domain = Eip712Domain::new(L2ChainId::from(chain_id)); + let signature = private_account + .get_pk_signer() + .sign_typed_data(&domain, &transaction_request) + .await + .unwrap(); + let encoded_tx = transaction_request.get_signed_bytes(&signature, L2ChainId::from(chain_id)); + + let (aa_txn_request, aa_hash) = + TransactionRequest::from_bytes(&encoded_tx, L2ChainId::from(chain_id)).unwrap(); + + let mut l2_tx = L2Tx::from_request(aa_txn_request, 100000).unwrap(); + l2_tx.set_input(encoded_tx, aa_hash); + + let transaction: Transaction = l2_tx.try_into().unwrap(); + vm.vm.push_transaction(transaction); + vm.vm.execute(VmExecutionMode::OneTx); + + assert_eq!( + vm.get_eth_balance(beneficiary.address), + U256::from(916375026) + ); + assert_eq!( + private_account_balance, + vm.get_eth_balance(private_account.address) + ); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/rollbacks.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/rollbacks.rs new file mode 100644 index 000000000000..4bee819e90e8 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/rollbacks.rs @@ -0,0 +1,263 @@ +use ethabi::Token; +use zksync_contracts::{get_loadnext_contract, test_contracts::LoadnextContractExecutionParams}; +use zksync_state::WriteStorage; +use zksync_types::{get_nonce_key, Execute, U256}; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_1::DynTracer, + tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + TxExecutionMode, VmExecutionMode, VmInterface, VmInterfaceHistoryEnabled, + }, + vm_1_4_1::{ + tests::{ + tester::{DeployContractsTx, TransactionTestInfo, TxModifier, TxType, VmTesterBuilder}, + utils::read_test_contract, + }, + types::internals::ZkSyncVmState, + BootloaderState, HistoryEnabled, HistoryMode, SimpleMemory, ToTracerPointer, VmTracer, + }, +}; + +#[test] +fn test_vm_rollbacks() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let mut account = vm.rich_accounts[0].clone(); + let counter = read_test_contract(); + let tx_0 = account.get_deploy_tx(&counter, None, TxType::L2).tx; + let tx_1 = account.get_deploy_tx(&counter, None, TxType::L2).tx; + let tx_2 = account.get_deploy_tx(&counter, None, TxType::L2).tx; + + let result_without_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_processed(tx_0.clone(), false), + TransactionTestInfo::new_processed(tx_1.clone(), false), + TransactionTestInfo::new_processed(tx_2.clone(), false), + ]); + + // reset vm + vm.reset_with_empty_storage(); + + let result_with_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongSignatureLength.into()), + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongMagicValue.into()), + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::WrongSignature.into()), + // The correct nonce is 0, this tx will fail + TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + // This tx will succeed + TransactionTestInfo::new_processed(tx_0.clone(), false), + // The correct nonce is 1, this tx will fail + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + // The correct nonce is 1, this tx will fail + TransactionTestInfo::new_rejected(tx_2.clone(), TxModifier::WrongNonce.into()), + // This tx will succeed + TransactionTestInfo::new_processed(tx_1, false), + // The correct nonce is 2, this tx will fail + TransactionTestInfo::new_rejected(tx_0.clone(), TxModifier::NonceReused.into()), + // This tx will succeed + TransactionTestInfo::new_processed(tx_2.clone(), false), + // This tx will fail + TransactionTestInfo::new_rejected(tx_2, TxModifier::NonceReused.into()), + TransactionTestInfo::new_rejected(tx_0, TxModifier::NonceReused.into()), + ]); + + assert_eq!(result_without_rollbacks, result_with_rollbacks); +} + +#[test] +fn test_vm_loadnext_rollbacks() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + let mut account = vm.rich_accounts[0].clone(); + + let loadnext_contract = get_loadnext_contract(); + let loadnext_constructor_data = &[Token::Uint(U256::from(100))]; + let DeployContractsTx { + tx: loadnext_deploy_tx, + address, + .. + } = account.get_deploy_tx_with_factory_deps( + &loadnext_contract.bytecode, + Some(loadnext_constructor_data), + loadnext_contract.factory_deps.clone(), + TxType::L2, + ); + + let loadnext_tx_1 = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: LoadnextContractExecutionParams { + reads: 100, + writes: 100, + events: 100, + hashes: 500, + recursive_calls: 10, + deploys: 60, + } + .to_bytes(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let loadnext_tx_2 = account.get_l2_tx_for_execute( + Execute { + contract_address: address, + calldata: LoadnextContractExecutionParams { + reads: 100, + writes: 100, + events: 100, + hashes: 500, + recursive_calls: 10, + deploys: 60, + } + .to_bytes(), + value: Default::default(), + factory_deps: None, + }, + None, + ); + + let result_without_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_processed(loadnext_deploy_tx.clone(), false), + TransactionTestInfo::new_processed(loadnext_tx_1.clone(), false), + TransactionTestInfo::new_processed(loadnext_tx_2.clone(), false), + ]); + + // reset vm + vm.reset_with_empty_storage(); + + let result_with_rollbacks = vm.execute_and_verify_txs(&vec![ + TransactionTestInfo::new_processed(loadnext_deploy_tx.clone(), false), + TransactionTestInfo::new_processed(loadnext_tx_1.clone(), true), + TransactionTestInfo::new_rejected( + loadnext_deploy_tx.clone(), + TxModifier::NonceReused.into(), + ), + TransactionTestInfo::new_processed(loadnext_tx_1, false), + TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), + TransactionTestInfo::new_processed(loadnext_tx_2.clone(), true), + TransactionTestInfo::new_rejected(loadnext_deploy_tx, TxModifier::NonceReused.into()), + TransactionTestInfo::new_processed(loadnext_tx_2, false), + ]); + + assert_eq!(result_without_rollbacks, result_with_rollbacks); +} + +// Testing tracer that does not allow the recursion to go deeper than a certain limit +struct MaxRecursionTracer { + max_recursion_depth: usize, +} + +/// Tracer responsible for calculating the number of storage invocations and +/// stopping the VM execution if the limit is reached. +impl DynTracer> for MaxRecursionTracer {} + +impl VmTracer for MaxRecursionTracer { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + let current_depth = state.local_state.callstack.depth(); + + if current_depth > self.max_recursion_depth { + TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish) + } else { + TracerExecutionStatus::Continue + } + } +} + +#[test] +fn test_layered_rollback() { + // This test checks that the layered rollbacks work correctly, i.e. + // the rollback by the operator will always revert all the changes + + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let account = &mut vm.rich_accounts[0]; + let loadnext_contract = get_loadnext_contract().bytecode; + + let DeployContractsTx { + tx: deploy_tx, + address, + .. + } = account.get_deploy_tx( + &loadnext_contract, + Some(&[Token::Uint(0.into())]), + TxType::L2, + ); + vm.vm.push_transaction(deploy_tx); + let deployment_res = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!deployment_res.result.is_failed(), "transaction failed"); + + let loadnext_transaction = account.get_loadnext_transaction( + address, + LoadnextContractExecutionParams { + writes: 1, + recursive_calls: 20, + ..LoadnextContractExecutionParams::empty() + }, + TxType::L2, + ); + + let nonce_val = vm + .vm + .state + .storage + .storage + .read_from_storage(&get_nonce_key(&account.address)); + + vm.vm.make_snapshot(); + + vm.vm.push_transaction(loadnext_transaction.clone()); + vm.vm.inspect( + MaxRecursionTracer { + max_recursion_depth: 15, + } + .into_tracer_pointer() + .into(), + VmExecutionMode::OneTx, + ); + + let nonce_val2 = vm + .vm + .state + .storage + .storage + .read_from_storage(&get_nonce_key(&account.address)); + + // The tracer stopped after the validation has passed, so nonce has already been increased + assert_eq!(nonce_val + U256::one(), nonce_val2, "nonce did not change"); + + vm.vm.rollback_to_the_latest_snapshot(); + + let nonce_val_after_rollback = vm + .vm + .state + .storage + .storage + .read_from_storage(&get_nonce_key(&account.address)); + + assert_eq!( + nonce_val, nonce_val_after_rollback, + "nonce changed after rollback" + ); + + vm.vm.push_transaction(loadnext_transaction); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed(), "transaction must not fail"); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/simple_execution.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/simple_execution.rs new file mode 100644 index 000000000000..745f5ab378de --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/simple_execution.rs @@ -0,0 +1,81 @@ +use crate::{ + interface::{ExecutionResult, VmExecutionMode, VmInterface}, + vm_1_4_1::{ + tests::tester::{TxType, VmTesterBuilder}, + HistoryDisabled, + }, +}; + +#[test] +fn estimate_fee() { + let mut vm_tester = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_deployer() + .with_random_rich_accounts(1) + .build(); + + vm_tester.deploy_test_contract(); + let account = &mut vm_tester.rich_accounts[0]; + + let tx = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + false, + Default::default(), + false, + TxType::L2, + ); + + vm_tester.vm.push_transaction(tx); + + let result = vm_tester.vm.execute(VmExecutionMode::OneTx); + assert!(matches!(result.result, ExecutionResult::Success { .. })); +} + +#[test] +fn simple_execute() { + let mut vm_tester = VmTesterBuilder::new(HistoryDisabled) + .with_empty_in_memory_storage() + .with_deployer() + .with_random_rich_accounts(1) + .build(); + + vm_tester.deploy_test_contract(); + + let account = &mut vm_tester.rich_accounts[0]; + + let tx1 = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + false, + Default::default(), + false, + TxType::L1 { serial_id: 1 }, + ); + + let tx2 = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + true, + Default::default(), + false, + TxType::L1 { serial_id: 1 }, + ); + + let tx3 = account.get_test_contract_transaction( + vm_tester.test_contract.unwrap(), + false, + Default::default(), + false, + TxType::L1 { serial_id: 1 }, + ); + let vm = &mut vm_tester.vm; + vm.push_transaction(tx1); + vm.push_transaction(tx2); + vm.push_transaction(tx3); + let tx = vm.execute(VmExecutionMode::OneTx); + assert!(matches!(tx.result, ExecutionResult::Success { .. })); + let tx = vm.execute(VmExecutionMode::OneTx); + assert!(matches!(tx.result, ExecutionResult::Revert { .. })); + let tx = vm.execute(VmExecutionMode::OneTx); + assert!(matches!(tx.result, ExecutionResult::Success { .. })); + let block_tip = vm.execute(VmExecutionMode::Batch); + assert!(matches!(block_tip.result, ExecutionResult::Success { .. })); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/inner_state.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/inner_state.rs new file mode 100644 index 000000000000..63e2be6a3620 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/inner_state.rs @@ -0,0 +1,131 @@ +use std::collections::HashMap; + +use zk_evm_1_4_1::{aux_structures::Timestamp, vm_state::VmLocalState}; +use zksync_state::WriteStorage; +use zksync_types::{StorageKey, StorageValue, U256}; + +use crate::{ + vm_1_4_1::{ + old_vm::{ + event_sink::InMemoryEventSink, + history_recorder::{AppDataFrameManagerWithHistory, HistoryRecorder}, + }, + utils::logs::StorageLogQuery, + HistoryEnabled, HistoryMode, SimpleMemory, Vm, + }, + HistoryMode as CommonHistoryMode, +}; + +#[derive(Clone, Debug)] +pub(crate) struct ModifiedKeysMap(HashMap); + +// We consider hashmaps to be equal even if there is a key +// that is not present in one but has zero value in another. +impl PartialEq for ModifiedKeysMap { + fn eq(&self, other: &Self) -> bool { + for (key, value) in self.0.iter() { + if *value != other.0.get(key).cloned().unwrap_or_default() { + return false; + } + } + for (key, value) in other.0.iter() { + if *value != self.0.get(key).cloned().unwrap_or_default() { + return false; + } + } + true + } +} + +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct DecommitterTestInnerState { + /// There is no way to "truly" compare the storage pointer, + /// so we just compare the modified keys. This is reasonable enough. + pub(crate) modified_storage_keys: ModifiedKeysMap, + pub(crate) known_bytecodes: HistoryRecorder>, H>, + pub(crate) decommitted_code_hashes: HistoryRecorder, HistoryEnabled>, +} + +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct StorageOracleInnerState { + /// There is no way to "truly" compare the storage pointer, + /// so we just compare the modified keys. This is reasonable enough. + pub(crate) modified_storage_keys: ModifiedKeysMap, + + pub(crate) frames_stack: AppDataFrameManagerWithHistory, H>, + + pub(crate) pre_paid_changes: HistoryRecorder, H>, + pub(crate) paid_changes: HistoryRecorder, H>, + pub(crate) initial_values: HistoryRecorder, H>, + pub(crate) returned_refunds: HistoryRecorder, H>, +} + +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct PrecompileProcessorTestInnerState { + pub(crate) timestamp_history: HistoryRecorder, H>, +} + +/// A struct that encapsulates the state of the VM's oracles +/// The state is to be used in tests. +#[derive(Clone, PartialEq, Debug)] +pub(crate) struct VmInstanceInnerState { + event_sink: InMemoryEventSink, + precompile_processor_state: PrecompileProcessorTestInnerState, + memory: SimpleMemory, + decommitter_state: DecommitterTestInnerState, + storage_oracle_state: StorageOracleInnerState, + local_state: VmLocalState, +} + +impl Vm { + // Dump inner state of the VM. + pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { + let event_sink = self.state.event_sink.clone(); + let precompile_processor_state = PrecompileProcessorTestInnerState { + timestamp_history: self.state.precompiles_processor.timestamp_history.clone(), + }; + let memory = self.state.memory.clone(); + let decommitter_state = DecommitterTestInnerState { + modified_storage_keys: ModifiedKeysMap( + self.state + .decommittment_processor + .get_storage() + .borrow() + .modified_storage_keys() + .clone(), + ), + known_bytecodes: self.state.decommittment_processor.known_bytecodes.clone(), + decommitted_code_hashes: self + .state + .decommittment_processor + .get_decommitted_code_hashes_with_history() + .clone(), + }; + let storage_oracle_state = StorageOracleInnerState { + modified_storage_keys: ModifiedKeysMap( + self.state + .storage + .storage + .get_ptr() + .borrow() + .modified_storage_keys() + .clone(), + ), + frames_stack: self.state.storage.frames_stack.clone(), + pre_paid_changes: self.state.storage.pre_paid_changes.clone(), + paid_changes: self.state.storage.paid_changes.clone(), + initial_values: self.state.storage.initial_values.clone(), + returned_refunds: self.state.storage.returned_refunds.clone(), + }; + let local_state = self.state.local_state.clone(); + + VmInstanceInnerState { + event_sink, + precompile_processor_state, + memory, + decommitter_state, + storage_oracle_state, + local_state, + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/mod.rs new file mode 100644 index 000000000000..c3cc5d8d9803 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/mod.rs @@ -0,0 +1,9 @@ +pub(crate) use transaction_test_info::{ExpectedError, TransactionTestInfo, TxModifier}; +pub(crate) use vm_tester::{ + default_l1_batch, get_empty_storage, InMemoryStorageView, VmTester, VmTesterBuilder, +}; +pub(crate) use zksync_test_account::{Account, DeployContractsTx, TxType}; + +mod inner_state; +mod transaction_test_info; +mod vm_tester; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/transaction_test_info.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/transaction_test_info.rs new file mode 100644 index 000000000000..443acf716763 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/transaction_test_info.rs @@ -0,0 +1,217 @@ +use zksync_types::{ExecuteTransactionCommon, Transaction}; + +use crate::{ + interface::{ + CurrentExecutionState, ExecutionResult, Halt, TxRevertReason, VmExecutionMode, + VmExecutionResultAndLogs, VmInterface, VmInterfaceHistoryEnabled, VmRevertReason, + }, + vm_1_4_1::{tests::tester::vm_tester::VmTester, HistoryEnabled}, +}; + +#[derive(Debug, Clone)] +pub(crate) enum TxModifier { + WrongSignatureLength, + WrongSignature, + WrongMagicValue, + WrongNonce, + NonceReused, +} + +#[derive(Debug, Clone)] +pub(crate) enum TxExpectedResult { + Rejected { error: ExpectedError }, + Processed { rollback: bool }, +} + +#[derive(Debug, Clone)] +pub(crate) struct TransactionTestInfo { + tx: Transaction, + result: TxExpectedResult, +} + +#[derive(Debug, Clone)] +pub(crate) struct ExpectedError { + pub(crate) revert_reason: TxRevertReason, + pub(crate) modifier: Option, +} + +impl From for ExpectedError { + fn from(value: TxModifier) -> Self { + let revert_reason = match value { + TxModifier::WrongSignatureLength => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Signature length is incorrect".to_string(), + data: vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 83, 105, 103, 110, 97, 116, 117, 114, 101, 32, + 108, 101, 110, 103, 116, 104, 32, 105, 115, 32, 105, 110, 99, 111, 114, 114, 101, 99, + 116, 0, 0, 0, + ], + }) + } + TxModifier::WrongSignature => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Account validation returned invalid magic value. Most often this means that the signature is incorrect".to_string(), + data: vec![], + }) + } + TxModifier::WrongMagicValue => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "v is neither 27 nor 28".to_string(), + data: vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 118, 32, 105, 115, 32, 110, 101, 105, 116, 104, + 101, 114, 32, 50, 55, 32, 110, 111, 114, 32, 50, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }) + + } + TxModifier::WrongNonce => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Incorrect nonce".to_string(), + data: vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 73, 110, 99, 111, 114, 114, 101, 99, 116, 32, 110, + 111, 110, 99, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }) + } + TxModifier::NonceReused => { + Halt::ValidationFailed(VmRevertReason::General { + msg: "Reusing the same nonce twice".to_string(), + data: vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 82, 101, 117, 115, 105, 110, 103, 32, 116, 104, + 101, 32, 115, 97, 109, 101, 32, 110, 111, 110, 99, 101, 32, 116, 119, 105, 99, 101, 0, + 0, 0, 0, + ], + }) + } + }; + + ExpectedError { + revert_reason: TxRevertReason::Halt(revert_reason), + modifier: Some(value), + } + } +} + +impl TransactionTestInfo { + pub(crate) fn new_rejected( + mut transaction: Transaction, + expected_error: ExpectedError, + ) -> Self { + transaction.common_data = match transaction.common_data { + ExecuteTransactionCommon::L2(mut data) => { + if let Some(modifier) = &expected_error.modifier { + match modifier { + TxModifier::WrongSignatureLength => { + data.signature = data.signature[..data.signature.len() - 20].to_vec() + } + TxModifier::WrongSignature => data.signature = vec![27u8; 65], + TxModifier::WrongMagicValue => data.signature = vec![1u8; 65], + TxModifier::WrongNonce => { + // Do not need to modify signature for nonce error + } + TxModifier::NonceReused => { + // Do not need to modify signature for nonce error + } + } + } + ExecuteTransactionCommon::L2(data) + } + _ => panic!("L1 transactions are not supported"), + }; + + Self { + tx: transaction, + result: TxExpectedResult::Rejected { + error: expected_error, + }, + } + } + + pub(crate) fn new_processed(transaction: Transaction, should_be_rollbacked: bool) -> Self { + Self { + tx: transaction, + result: TxExpectedResult::Processed { + rollback: should_be_rollbacked, + }, + } + } + + fn verify_result(&self, result: &VmExecutionResultAndLogs) { + match &self.result { + TxExpectedResult::Rejected { error } => match &result.result { + ExecutionResult::Success { .. } => { + panic!("Transaction should be reverted {:?}", self.tx.nonce()) + } + ExecutionResult::Revert { output } => match &error.revert_reason { + TxRevertReason::TxReverted(expected) => { + assert_eq!(output, expected) + } + _ => { + panic!("Error types mismatch"); + } + }, + ExecutionResult::Halt { reason } => match &error.revert_reason { + TxRevertReason::Halt(expected) => { + assert_eq!(reason, expected) + } + _ => { + panic!("Error types mismatch"); + } + }, + }, + TxExpectedResult::Processed { .. } => { + assert!(!result.result.is_failed()); + } + } + } + + fn should_rollback(&self) -> bool { + match &self.result { + TxExpectedResult::Rejected { .. } => true, + TxExpectedResult::Processed { rollback } => *rollback, + } + } +} + +impl VmTester { + pub(crate) fn execute_and_verify_txs( + &mut self, + txs: &[TransactionTestInfo], + ) -> CurrentExecutionState { + for tx_test_info in txs { + self.execute_tx_and_verify(tx_test_info.clone()); + } + self.vm.execute(VmExecutionMode::Batch); + let mut state = self.vm.get_current_execution_state(); + state.used_contract_hashes.sort(); + state + } + + pub(crate) fn execute_tx_and_verify( + &mut self, + tx_test_info: TransactionTestInfo, + ) -> VmExecutionResultAndLogs { + let inner_state_before = self.vm.dump_inner_state(); + self.vm.make_snapshot(); + self.vm.push_transaction(tx_test_info.tx.clone()); + let result = self.vm.execute(VmExecutionMode::OneTx); + tx_test_info.verify_result(&result); + if tx_test_info.should_rollback() { + self.vm.rollback_to_the_latest_snapshot(); + let inner_state_after = self.vm.dump_inner_state(); + assert_eq!( + inner_state_before, inner_state_after, + "Inner state before and after rollback should be equal" + ); + } + result + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/vm_tester.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/vm_tester.rs new file mode 100644 index 000000000000..4da556114589 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/tester/vm_tester.rs @@ -0,0 +1,298 @@ +use std::marker::PhantomData; + +use zksync_contracts::BaseSystemContracts; +use zksync_state::{InMemoryStorage, StoragePtr, StorageView, WriteStorage}; +use zksync_types::{ + block::MiniblockHasher, + fee_model::BatchFeeInput, + get_code_key, get_is_account_key, + helpers::unix_timestamp_ms, + utils::{deployed_address_create, storage_key_for_eth_balance}, + Address, L1BatchNumber, L2ChainId, MiniblockNumber, Nonce, ProtocolVersionId, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, u256_to_h256}; + +use crate::{ + interface::{ + L1BatchEnv, L2Block, L2BlockEnv, SystemEnv, TxExecutionMode, VmExecutionMode, VmInterface, + }, + vm_1_4_1::{ + constants::BLOCK_GAS_LIMIT, + tests::{ + tester::{Account, TxType}, + utils::read_test_contract, + }, + utils::l2_blocks::load_last_l2_block, + Vm, + }, + HistoryMode, +}; + +pub(crate) type InMemoryStorageView = StorageView; + +pub(crate) struct VmTester { + pub(crate) vm: Vm, + pub(crate) storage: StoragePtr, + pub(crate) fee_account: Address, + pub(crate) deployer: Option, + pub(crate) test_contract: Option
    , + pub(crate) rich_accounts: Vec, + pub(crate) custom_contracts: Vec, + _phantom: std::marker::PhantomData, +} + +impl VmTester { + pub(crate) fn deploy_test_contract(&mut self) { + let contract = read_test_contract(); + let tx = self + .deployer + .as_mut() + .expect("You have to initialize builder with deployer") + .get_deploy_tx(&contract, None, TxType::L2) + .tx; + let nonce = tx.nonce().unwrap().0.into(); + self.vm.push_transaction(tx); + self.vm.execute(VmExecutionMode::OneTx); + let deployed_address = + deployed_address_create(self.deployer.as_ref().unwrap().address, nonce); + self.test_contract = Some(deployed_address); + } + + pub(crate) fn reset_with_empty_storage(&mut self) { + self.storage = StorageView::new(get_empty_storage()).to_rc_ptr(); + self.reset_state(false); + } + + /// Reset the state of the VM to the initial state. + /// If `use_latest_l2_block` is true, then the VM will use the latest L2 block from storage, + /// otherwise it will use the first L2 block of l1 batch env + pub(crate) fn reset_state(&mut self, use_latest_l2_block: bool) { + for account in self.rich_accounts.iter_mut() { + account.nonce = Nonce(0); + make_account_rich(self.storage.clone(), account); + } + if let Some(deployer) = &self.deployer { + make_account_rich(self.storage.clone(), deployer); + } + + if !self.custom_contracts.is_empty() { + println!("Inserting custom contracts is not yet supported") + // `insert_contracts(&mut self.storage, &self.custom_contracts);` + } + + let mut l1_batch = self.vm.batch_env.clone(); + if use_latest_l2_block { + let last_l2_block = load_last_l2_block(self.storage.clone()).unwrap_or(L2Block { + number: 0, + timestamp: 0, + hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + }); + l1_batch.first_l2_block = L2BlockEnv { + number: last_l2_block.number + 1, + timestamp: std::cmp::max(last_l2_block.timestamp + 1, l1_batch.timestamp), + prev_block_hash: last_l2_block.hash, + max_virtual_blocks_to_create: 1, + }; + } + + let vm = Vm::new(l1_batch, self.vm.system_env.clone(), self.storage.clone()); + + if self.test_contract.is_some() { + self.deploy_test_contract(); + } + + self.vm = vm; + } +} + +pub(crate) type ContractsToDeploy = (Vec, Address, bool); + +pub(crate) struct VmTesterBuilder { + storage: Option, + l1_batch_env: Option, + system_env: SystemEnv, + deployer: Option, + rich_accounts: Vec, + custom_contracts: Vec, + _phantom: PhantomData, +} + +impl Clone for VmTesterBuilder { + fn clone(&self) -> Self { + Self { + storage: None, + l1_batch_env: self.l1_batch_env.clone(), + system_env: self.system_env.clone(), + deployer: self.deployer.clone(), + rich_accounts: self.rich_accounts.clone(), + custom_contracts: self.custom_contracts.clone(), + _phantom: PhantomData, + } + } +} + +#[allow(dead_code)] +impl VmTesterBuilder { + pub(crate) fn new(_: H) -> Self { + Self { + storage: None, + l1_batch_env: None, + system_env: SystemEnv { + zk_porter_available: false, + version: ProtocolVersionId::latest(), + base_system_smart_contracts: BaseSystemContracts::playground(), + gas_limit: BLOCK_GAS_LIMIT, + execution_mode: TxExecutionMode::VerifyExecute, + default_validation_computational_gas_limit: BLOCK_GAS_LIMIT, + chain_id: L2ChainId::from(270), + }, + deployer: None, + rich_accounts: vec![], + custom_contracts: vec![], + _phantom: PhantomData, + } + } + + pub(crate) fn with_l1_batch_env(mut self, l1_batch_env: L1BatchEnv) -> Self { + self.l1_batch_env = Some(l1_batch_env); + self + } + + pub(crate) fn with_system_env(mut self, system_env: SystemEnv) -> Self { + self.system_env = system_env; + self + } + + pub(crate) fn with_storage(mut self, storage: InMemoryStorage) -> Self { + self.storage = Some(storage); + self + } + + pub(crate) fn with_base_system_smart_contracts( + mut self, + base_system_smart_contracts: BaseSystemContracts, + ) -> Self { + self.system_env.base_system_smart_contracts = base_system_smart_contracts; + self + } + + pub(crate) fn with_gas_limit(mut self, gas_limit: u32) -> Self { + self.system_env.gas_limit = gas_limit; + self + } + + pub(crate) fn with_execution_mode(mut self, execution_mode: TxExecutionMode) -> Self { + self.system_env.execution_mode = execution_mode; + self + } + + pub(crate) fn with_empty_in_memory_storage(mut self) -> Self { + self.storage = Some(get_empty_storage()); + self + } + + pub(crate) fn with_random_rich_accounts(mut self, number: u32) -> Self { + for _ in 0..number { + let account = Account::random(); + self.rich_accounts.push(account); + } + self + } + + pub(crate) fn with_rich_accounts(mut self, accounts: Vec) -> Self { + self.rich_accounts.extend(accounts); + self + } + + pub(crate) fn with_deployer(mut self) -> Self { + let deployer = Account::random(); + self.deployer = Some(deployer); + self + } + + pub(crate) fn with_custom_contracts(mut self, contracts: Vec) -> Self { + self.custom_contracts = contracts; + self + } + + pub(crate) fn build(self) -> VmTester { + let l1_batch_env = self + .l1_batch_env + .unwrap_or_else(|| default_l1_batch(L1BatchNumber(1))); + + let mut raw_storage = self.storage.unwrap_or_else(get_empty_storage); + insert_contracts(&mut raw_storage, &self.custom_contracts); + let storage_ptr = StorageView::new(raw_storage).to_rc_ptr(); + for account in self.rich_accounts.iter() { + make_account_rich(storage_ptr.clone(), account); + } + if let Some(deployer) = &self.deployer { + make_account_rich(storage_ptr.clone(), deployer); + } + let fee_account = l1_batch_env.fee_account; + + let vm = Vm::new(l1_batch_env, self.system_env, storage_ptr.clone()); + + VmTester { + vm, + storage: storage_ptr, + fee_account, + deployer: self.deployer, + test_contract: None, + rich_accounts: self.rich_accounts.clone(), + custom_contracts: self.custom_contracts.clone(), + _phantom: PhantomData, + } + } +} + +pub(crate) fn default_l1_batch(number: L1BatchNumber) -> L1BatchEnv { + let timestamp = unix_timestamp_ms(); + L1BatchEnv { + previous_batch_hash: None, + number, + timestamp, + fee_input: BatchFeeInput::l1_pegged( + 50_000_000_000, // 50 gwei + 250_000_000, // 0.25 gwei + ), + fee_account: Address::random(), + enforced_base_fee: None, + first_l2_block: L2BlockEnv { + number: 1, + timestamp, + prev_block_hash: MiniblockHasher::legacy_hash(MiniblockNumber(0)), + max_virtual_blocks_to_create: 100, + }, + } +} + +pub(crate) fn make_account_rich(storage: StoragePtr, account: &Account) { + let key = storage_key_for_eth_balance(&account.address); + storage + .as_ref() + .borrow_mut() + .set_value(key, u256_to_h256(U256::from(10u64.pow(19)))); +} + +pub(crate) fn get_empty_storage() -> InMemoryStorage { + InMemoryStorage::with_system_contracts(hash_bytecode) +} + +// Inserts the contracts into the test environment, bypassing the +// deployer system contract. Besides the reference to storage +// it accepts a `contracts` tuple of information about the contract +// and whether or not it is an account. +fn insert_contracts(raw_storage: &mut InMemoryStorage, contracts: &[ContractsToDeploy]) { + for (contract, address, is_account) in contracts { + let deployer_code_key = get_code_key(address); + raw_storage.set_value(deployer_code_key, hash_bytecode(contract)); + + if *is_account { + let is_account_key = get_is_account_key(address); + raw_storage.set_value(is_account_key, u256_to_h256(1_u32.into())); + } + + raw_storage.store_factory_dep(hash_bytecode(contract), contract.clone()); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/tracing_execution_error.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/tracing_execution_error.rs new file mode 100644 index 000000000000..02c7590c1bea --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/tracing_execution_error.rs @@ -0,0 +1,54 @@ +use zksync_types::{Execute, H160}; + +use crate::{ + interface::{TxExecutionMode, TxRevertReason, VmRevertReason}, + vm_1_4_1::{ + tests::{ + tester::{ExpectedError, TransactionTestInfo, VmTesterBuilder}, + utils::{get_execute_error_calldata, read_error_contract, BASE_SYSTEM_CONTRACTS}, + }, + HistoryEnabled, + }, +}; + +#[test] +fn test_tracing_of_execution_errors() { + let contract_address = H160::random(); + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_base_system_smart_contracts(BASE_SYSTEM_CONTRACTS.clone()) + .with_custom_contracts(vec![(read_error_contract(), contract_address, false)]) + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_deployer() + .with_random_rich_accounts(1) + .build(); + + let account = &mut vm.rich_accounts[0]; + + let tx = account.get_l2_tx_for_execute( + Execute { + contract_address, + calldata: get_execute_error_calldata(), + value: Default::default(), + factory_deps: Some(vec![]), + }, + None, + ); + + vm.execute_tx_and_verify(TransactionTestInfo::new_rejected( + tx, + ExpectedError { + revert_reason: TxRevertReason::TxReverted(VmRevertReason::General { + msg: "short".to_string(), + data: vec![ + 8, 195, 121, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 115, 104, 111, 114, 116, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + ], + }), + modifier: None, + }, + )); +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/upgrade.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/upgrade.rs new file mode 100644 index 000000000000..2c2b341338ae --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/upgrade.rs @@ -0,0 +1,355 @@ +use zk_evm_1_4_1::aux_structures::Timestamp; +use zksync_contracts::{deployer_contract, load_sys_contract, read_bytecode}; +use zksync_state::WriteStorage; +use zksync_test_account::TxType; +use zksync_types::{ + ethabi::{Contract, Token}, + get_code_key, get_known_code_key, + protocol_version::ProtocolUpgradeTxCommonData, + Address, Execute, ExecuteTransactionCommon, Transaction, COMPLEX_UPGRADER_ADDRESS, + CONTRACT_DEPLOYER_ADDRESS, CONTRACT_FORCE_DEPLOYER_ADDRESS, H160, H256, + REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; + +use super::utils::{get_complex_upgrade_abi, read_test_contract}; +use crate::{ + interface::{ + ExecutionResult, Halt, TxExecutionMode, VmExecutionMode, VmInterface, + VmInterfaceHistoryEnabled, + }, + vm_1_4_1::{ + tests::{ + tester::VmTesterBuilder, + utils::{read_complex_upgrade, verify_required_storage}, + }, + HistoryEnabled, + }, +}; + +/// In this test we ensure that the requirements for protocol upgrade transactions are enforced by the bootloader: +/// - This transaction must be the only one in block +/// - If present, this transaction must be the first one in block +#[test] +fn test_protocol_upgrade_is_first() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let bytecode_hash = hash_bytecode(&read_test_contract()); + vm.vm + .storage + .borrow_mut() + .set_value(get_known_code_key(&bytecode_hash), u256_to_h256(1.into())); + + // Here we just use some random transaction of protocol upgrade type: + let protocol_upgrade_transaction = get_forced_deploy_tx(&[ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash, + // The address on which to deploy the bytecode hash to + address: H160::random(), + // Whether to run the constructor on the force deployment + call_constructor: false, + // The value with which to initialize a contract + value: U256::zero(), + // The constructor calldata + input: vec![], + }]); + + // Another random upgrade transaction + let another_protocol_upgrade_transaction = get_forced_deploy_tx(&[ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash, + // The address on which to deploy the bytecode hash to + address: H160::random(), + // Whether to run the constructor on the force deployment + call_constructor: false, + // The value with which to initialize a contract + value: U256::zero(), + // The constructor calldata + input: vec![], + }]); + + let normal_l1_transaction = vm.rich_accounts[0] + .get_deploy_tx(&read_test_contract(), None, TxType::L1 { serial_id: 0 }) + .tx; + + let expected_error = + Halt::UnexpectedVMBehavior("Assertion error: Protocol upgrade tx not first".to_string()); + + vm.vm.make_snapshot(); + // Test 1: there must be only one system transaction in block + vm.vm.push_transaction(protocol_upgrade_transaction.clone()); + vm.vm.push_transaction(normal_l1_transaction.clone()); + vm.vm.push_transaction(another_protocol_upgrade_transaction); + + vm.vm.execute(VmExecutionMode::OneTx); + vm.vm.execute(VmExecutionMode::OneTx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert_eq!( + result.result, + ExecutionResult::Halt { + reason: expected_error.clone() + } + ); + + // Test 2: the protocol upgrade tx must be the first one in block + vm.vm.rollback_to_the_latest_snapshot(); + vm.vm.make_snapshot(); + vm.vm.push_transaction(normal_l1_transaction.clone()); + vm.vm.push_transaction(protocol_upgrade_transaction.clone()); + + vm.vm.execute(VmExecutionMode::OneTx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert_eq!( + result.result, + ExecutionResult::Halt { + reason: expected_error + } + ); + + vm.vm.rollback_to_the_latest_snapshot(); + vm.vm.make_snapshot(); + vm.vm.push_transaction(protocol_upgrade_transaction); + vm.vm.push_transaction(normal_l1_transaction); + + vm.vm.execute(VmExecutionMode::OneTx); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!(!result.result.is_failed()); +} + +/// In this test we try to test how force deployments could be done via protocol upgrade transactions. +#[test] +fn test_force_deploy_upgrade() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let storage_view = vm.storage.clone(); + let bytecode_hash = hash_bytecode(&read_test_contract()); + + let known_code_key = get_known_code_key(&bytecode_hash); + // It is generally expected that all the keys will be set as known prior to the protocol upgrade. + storage_view + .borrow_mut() + .set_value(known_code_key, u256_to_h256(1.into())); + drop(storage_view); + + let address_to_deploy = H160::random(); + // Here we just use some random transaction of protocol upgrade type: + let transaction = get_forced_deploy_tx(&[ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash, + // The address on which to deploy the bytecode hash to + address: address_to_deploy, + // Whether to run the constructor on the force deployment + call_constructor: false, + // The value with which to initialize a contract + value: U256::zero(), + // The constructor calldata + input: vec![], + }]); + + vm.vm.push_transaction(transaction); + + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!( + !result.result.is_failed(), + "The force upgrade was not successful" + ); + + let expected_slots = vec![(bytecode_hash, get_code_key(&address_to_deploy))]; + + // Verify that the bytecode has been set correctly + verify_required_storage(&vm.vm.state, expected_slots); +} + +/// Here we show how the work with the complex upgrader could be done +#[test] +fn test_complex_upgrader() { + let mut vm = VmTesterBuilder::new(HistoryEnabled) + .with_empty_in_memory_storage() + .with_execution_mode(TxExecutionMode::VerifyExecute) + .with_random_rich_accounts(1) + .build(); + + let storage_view = vm.storage.clone(); + + let bytecode_hash = hash_bytecode(&read_complex_upgrade()); + let msg_sender_test_hash = hash_bytecode(&read_msg_sender_test()); + + // Let's assume that the bytecode for the implementation of the complex upgrade + // is already deployed in some address in user space + let upgrade_impl = H160::random(); + let account_code_key = get_code_key(&upgrade_impl); + + storage_view + .borrow_mut() + .set_value(get_known_code_key(&bytecode_hash), u256_to_h256(1.into())); + storage_view.borrow_mut().set_value( + get_known_code_key(&msg_sender_test_hash), + u256_to_h256(1.into()), + ); + storage_view + .borrow_mut() + .set_value(account_code_key, bytecode_hash); + drop(storage_view); + + vm.vm.state.decommittment_processor.populate( + vec![ + ( + h256_to_u256(bytecode_hash), + bytes_to_be_words(read_complex_upgrade()), + ), + ( + h256_to_u256(msg_sender_test_hash), + bytes_to_be_words(read_msg_sender_test()), + ), + ], + Timestamp(0), + ); + + let address_to_deploy1 = H160::random(); + let address_to_deploy2 = H160::random(); + + let transaction = get_complex_upgrade_tx( + upgrade_impl, + address_to_deploy1, + address_to_deploy2, + bytecode_hash, + ); + + vm.vm.push_transaction(transaction); + let result = vm.vm.execute(VmExecutionMode::OneTx); + assert!( + !result.result.is_failed(), + "The force upgrade was not successful" + ); + + let expected_slots = vec![ + (bytecode_hash, get_code_key(&address_to_deploy1)), + (bytecode_hash, get_code_key(&address_to_deploy2)), + ]; + + // Verify that the bytecode has been set correctly + verify_required_storage(&vm.vm.state, expected_slots); +} + +#[derive(Debug, Clone)] +struct ForceDeployment { + // The bytecode hash to put on an address + bytecode_hash: H256, + // The address on which to deploy the bytecode hash to + address: Address, + // Whether to run the constructor on the force deployment + call_constructor: bool, + // The value with which to initialize a contract + value: U256, + // The constructor calldata + input: Vec, +} + +fn get_forced_deploy_tx(deployment: &[ForceDeployment]) -> Transaction { + let deployer = deployer_contract(); + let contract_function = deployer.function("forceDeployOnAddresses").unwrap(); + + let encoded_deployments: Vec<_> = deployment + .iter() + .map(|deployment| { + Token::Tuple(vec![ + Token::FixedBytes(deployment.bytecode_hash.as_bytes().to_vec()), + Token::Address(deployment.address), + Token::Bool(deployment.call_constructor), + Token::Uint(deployment.value), + Token::Bytes(deployment.input.clone()), + ]) + }) + .collect(); + + let params = [Token::Array(encoded_deployments)]; + + let calldata = contract_function + .encode_input(¶ms) + .expect("failed to encode parameters"); + + let execute = Execute { + contract_address: CONTRACT_DEPLOYER_ADDRESS, + calldata, + factory_deps: None, + value: U256::zero(), + }; + + Transaction { + common_data: ExecuteTransactionCommon::ProtocolUpgrade(ProtocolUpgradeTxCommonData { + sender: CONTRACT_FORCE_DEPLOYER_ADDRESS, + gas_limit: U256::from(200_000_000u32), + gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), + ..Default::default() + }), + execute, + received_timestamp_ms: 0, + raw_bytes: None, + } +} + +// Returns the transaction that performs a complex protocol upgrade. +// The first param is the address of the implementation of the complex upgrade +// in user-space, while the next 3 params are params of the implementation itself +// For the explanation for the parameters, please refer to: +// etc/contracts-test-data/complex-upgrade/complex-upgrade.sol +fn get_complex_upgrade_tx( + implementation_address: Address, + address1: Address, + address2: Address, + bytecode_hash: H256, +) -> Transaction { + let impl_contract = get_complex_upgrade_abi(); + let impl_function = impl_contract.function("someComplexUpgrade").unwrap(); + let impl_calldata = impl_function + .encode_input(&[ + Token::Address(address1), + Token::Address(address2), + Token::FixedBytes(bytecode_hash.as_bytes().to_vec()), + ]) + .unwrap(); + + let complex_upgrader = get_complex_upgrader_abi(); + let upgrade_function = complex_upgrader.function("upgrade").unwrap(); + let complex_upgrader_calldata = upgrade_function + .encode_input(&[ + Token::Address(implementation_address), + Token::Bytes(impl_calldata), + ]) + .unwrap(); + + let execute = Execute { + contract_address: COMPLEX_UPGRADER_ADDRESS, + calldata: complex_upgrader_calldata, + factory_deps: None, + value: U256::zero(), + }; + + Transaction { + common_data: ExecuteTransactionCommon::ProtocolUpgrade(ProtocolUpgradeTxCommonData { + sender: CONTRACT_FORCE_DEPLOYER_ADDRESS, + gas_limit: U256::from(200_000_000u32), + gas_per_pubdata_limit: REQUIRED_L1_TO_L2_GAS_PER_PUBDATA_BYTE.into(), + ..Default::default() + }), + execute, + received_timestamp_ms: 0, + raw_bytes: None, + } +} + +fn read_msg_sender_test() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/msg-sender.sol/MsgSenderTest.json") +} + +fn get_complex_upgrader_abi() -> Contract { + load_sys_contract("ComplexUpgrader") +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tests/utils.rs b/core/lib/multivm/src/versions/vm_1_4_1/tests/utils.rs new file mode 100644 index 000000000000..f0fc0f07f2b5 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tests/utils.rs @@ -0,0 +1,121 @@ +use ethabi::Contract; +use once_cell::sync::Lazy; +use zksync_contracts::{ + load_contract, read_bytecode, read_zbin_bytecode, BaseSystemContracts, SystemContractCode, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + utils::storage_key_for_standard_token_balance, AccountTreeId, Address, StorageKey, H256, U256, +}; +use zksync_utils::{bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256, u256_to_h256}; + +use crate::vm_1_4_1::{ + tests::tester::InMemoryStorageView, types::internals::ZkSyncVmState, HistoryMode, +}; + +pub(crate) static BASE_SYSTEM_CONTRACTS: Lazy = + Lazy::new(BaseSystemContracts::load_from_disk); + +// Probably make it a part of vm tester +pub(crate) fn verify_required_storage( + state: &ZkSyncVmState, + required_values: Vec<(H256, StorageKey)>, +) { + for (required_value, key) in required_values { + let current_value = state.storage.storage.read_from_storage(&key); + + assert_eq!( + u256_to_h256(current_value), + required_value, + "Invalid value at key {key:?}" + ); + } +} + +pub(crate) fn verify_required_memory( + state: &ZkSyncVmState, + required_values: Vec<(U256, u32, u32)>, +) { + for (required_value, memory_page, cell) in required_values { + let current_value = state + .memory + .read_slot(memory_page as usize, cell as usize) + .value; + assert_eq!(current_value, required_value); + } +} + +pub(crate) fn get_balance( + token_id: AccountTreeId, + account: &Address, + main_storage: StoragePtr, +) -> U256 { + let key = storage_key_for_standard_token_balance(token_id, account); + h256_to_u256(main_storage.borrow_mut().read_value(&key)) +} + +pub(crate) fn read_test_contract() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/counter/counter.sol/Counter.json") +} + +pub(crate) fn get_bootloader(test: &str) -> SystemContractCode { + let bootloader_code = read_zbin_bytecode(format!( + "contracts/system-contracts/bootloader/tests/artifacts/{}.yul.zbin", + test + )); + + let bootloader_hash = hash_bytecode(&bootloader_code); + SystemContractCode { + code: bytes_to_be_words(bootloader_code), + hash: bootloader_hash, + } +} + +pub(crate) fn read_nonce_holder_tester() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/custom-account/nonce-holder-test.sol/NonceHolderTest.json") +} + +pub(crate) fn read_error_contract() -> Vec { + read_bytecode( + "etc/contracts-test-data/artifacts-zk/contracts/error/error.sol/SimpleRequire.json", + ) +} + +pub(crate) fn get_execute_error_calldata() -> Vec { + let test_contract = load_contract( + "etc/contracts-test-data/artifacts-zk/contracts/error/error.sol/SimpleRequire.json", + ); + + let function = test_contract.function("require_short").unwrap(); + + function + .encode_input(&[]) + .expect("failed to encode parameters") +} + +pub(crate) fn read_many_owners_custom_account_contract() -> (Vec, Contract) { + let path = "etc/contracts-test-data/artifacts-zk/contracts/custom-account/many-owners-custom-account.sol/ManyOwnersCustomAccount.json"; + (read_bytecode(path), load_contract(path)) +} + +pub(crate) fn read_max_depth_contract() -> Vec { + read_zbin_bytecode( + "core/tests/ts-integration/contracts/zkasm/artifacts/deep_stak.zkasm/deep_stak.zkasm.zbin", + ) +} + +pub(crate) fn read_precompiles_contract() -> Vec { + read_bytecode( + "etc/contracts-test-data/artifacts-zk/contracts/precompiles/precompiles.sol/Precompiles.json", + ) +} + +pub(crate) fn read_complex_upgrade() -> Vec { + read_bytecode("etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json") +} + +pub(crate) fn get_complex_upgrade_abi() -> Contract { + load_contract( + "etc/contracts-test-data/artifacts-zk/contracts/complex-upgrade/complex-upgrade.sol/ComplexUpgrade.json" + ) +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_capacity.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_capacity.rs new file mode 100644 index 000000000000..422294dd2065 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_capacity.rs @@ -0,0 +1,67 @@ +use zkevm_test_harness_1_4_1::{geometry_config::get_geometry_config, toolset::GeometryConfig}; +use zksync_types::circuit::{CircuitCycleStatistic, CircuitStatistic}; + +// "Rich addressing" opcodes are opcodes that can write their return value/read the input onto the stack +// and so take 1-2 RAM permutations more than an average opcode. +// In the worst case, a rich addressing may take 3 ram permutations +// (1 for reading the opcode, 1 for writing input value, 1 for writing output value). +pub(crate) const RICH_ADDRESSING_OPCODE_RAM_CYCLES: u32 = 3; + +pub(crate) const AVERAGE_OPCODE_RAM_CYCLES: u32 = 1; + +pub(crate) const STORAGE_READ_RAM_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_LOG_DEMUXER_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_STORAGE_SORTER_CYCLES: u32 = 1; +pub(crate) const STORAGE_READ_STORAGE_APPLICATION_CYCLES: u32 = 1; + +pub(crate) const EVENT_RAM_CYCLES: u32 = 1; +pub(crate) const EVENT_LOG_DEMUXER_CYCLES: u32 = 2; +pub(crate) const EVENT_EVENTS_SORTER_CYCLES: u32 = 2; + +pub(crate) const STORAGE_WRITE_RAM_CYCLES: u32 = 1; +pub(crate) const STORAGE_WRITE_LOG_DEMUXER_CYCLES: u32 = 2; +pub(crate) const STORAGE_WRITE_STORAGE_SORTER_CYCLES: u32 = 2; +pub(crate) const STORAGE_WRITE_STORAGE_APPLICATION_CYCLES: u32 = 2; + +pub(crate) const FAR_CALL_RAM_CYCLES: u32 = 1; +pub(crate) const FAR_CALL_STORAGE_SORTER_CYCLES: u32 = 1; +pub(crate) const FAR_CALL_CODE_DECOMMITTER_SORTER_CYCLES: u32 = 1; + +// 5 RAM permutations, because: 1 to read opcode + 2 reads + 2 writes. +// 2 reads and 2 writes are needed because unaligned access is implemented with +// aligned queries. +pub(crate) const UMA_WRITE_RAM_CYCLES: u32 = 5; + +// 3 RAM permutations, because: 1 to read opcode + 2 reads. +// 2 reads are needed because unaligned access is implemented with aligned queries. +pub(crate) const UMA_READ_RAM_CYCLES: u32 = 3; + +pub(crate) const PRECOMPILE_RAM_CYCLES: u32 = 1; +pub(crate) const PRECOMPILE_LOG_DEMUXER_CYCLES: u32 = 1; + +const GEOMETRY_CONFIG: GeometryConfig = get_geometry_config(); + +pub(crate) fn circuit_statistic_from_cycles(cycles: CircuitCycleStatistic) -> CircuitStatistic { + CircuitStatistic { + main_vm: cycles.main_vm_cycles as f32 / GEOMETRY_CONFIG.cycles_per_vm_snapshot as f32, + ram_permutation: cycles.ram_permutation_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_ram_permutation as f32, + storage_application: cycles.storage_application_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_storage_application as f32, + storage_sorter: cycles.storage_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_storage_sorter as f32, + code_decommitter: cycles.code_decommitter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_code_decommitter as f32, + code_decommitter_sorter: cycles.code_decommitter_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_code_decommitter_sorter as f32, + log_demuxer: cycles.log_demuxer_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_log_demuxer as f32, + events_sorter: cycles.events_sorter_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_events_or_l1_messages_sorter as f32, + keccak256: cycles.keccak256_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_keccak256_circuit as f32, + ecrecover: cycles.ecrecover_cycles as f32 + / GEOMETRY_CONFIG.cycles_per_ecrecover_circuit as f32, + sha256: cycles.sha256_cycles as f32 / GEOMETRY_CONFIG.cycles_per_sha256_circuit as f32, + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_tracer.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_tracer.rs new file mode 100644 index 000000000000..06244179aa80 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/circuits_tracer.rs @@ -0,0 +1,233 @@ +use std::marker::PhantomData; + +use zk_evm_1_4_1::{ + tracing::{BeforeExecutionData, VmLocalStateData}, + zk_evm_abstractions::precompiles::PrecompileAddress, + zkevm_opcode_defs::{LogOpcode, Opcode, UMAOpcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::circuit::CircuitCycleStatistic; + +use super::circuits_capacity::*; +use crate::{ + interface::{dyn_tracers::vm_1_4_1::DynTracer, tracer::TracerExecutionStatus}, + vm_1_4_1::{ + bootloader_state::BootloaderState, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::traits::VmTracer, + types::internals::ZkSyncVmState, + }, +}; + +/// Tracer responsible for collecting information about refunds. +#[derive(Debug)] +pub(crate) struct CircuitsTracer { + pub(crate) statistics: CircuitCycleStatistic, + last_decommitment_history_entry_checked: Option, + last_written_keys_history_entry_checked: Option, + last_read_keys_history_entry_checked: Option, + last_precompile_inner_entry_checked: Option, + _phantom_data: PhantomData<(S, H)>, +} + +impl DynTracer> for CircuitsTracer { + fn before_execution( + &mut self, + _state: VmLocalStateData<'_>, + data: BeforeExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + self.statistics.main_vm_cycles += 1; + + match data.opcode.variant.opcode { + Opcode::Nop(_) + | Opcode::Add(_) + | Opcode::Sub(_) + | Opcode::Mul(_) + | Opcode::Div(_) + | Opcode::Jump(_) + | Opcode::Binop(_) + | Opcode::Shift(_) + | Opcode::Ptr(_) => { + self.statistics.ram_permutation_cycles += RICH_ADDRESSING_OPCODE_RAM_CYCLES; + } + Opcode::Context(_) | Opcode::Ret(_) | Opcode::NearCall(_) => { + self.statistics.ram_permutation_cycles += AVERAGE_OPCODE_RAM_CYCLES; + } + Opcode::Log(LogOpcode::StorageRead) => { + self.statistics.ram_permutation_cycles += STORAGE_READ_RAM_CYCLES; + self.statistics.log_demuxer_cycles += STORAGE_READ_LOG_DEMUXER_CYCLES; + self.statistics.storage_sorter_cycles += STORAGE_READ_STORAGE_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::StorageWrite) => { + self.statistics.ram_permutation_cycles += STORAGE_WRITE_RAM_CYCLES; + self.statistics.log_demuxer_cycles += STORAGE_WRITE_LOG_DEMUXER_CYCLES; + self.statistics.storage_sorter_cycles += STORAGE_WRITE_STORAGE_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::ToL1Message) | Opcode::Log(LogOpcode::Event) => { + self.statistics.ram_permutation_cycles += EVENT_RAM_CYCLES; + self.statistics.log_demuxer_cycles += EVENT_LOG_DEMUXER_CYCLES; + self.statistics.events_sorter_cycles += EVENT_EVENTS_SORTER_CYCLES; + } + Opcode::Log(LogOpcode::PrecompileCall) => { + self.statistics.ram_permutation_cycles += PRECOMPILE_RAM_CYCLES; + self.statistics.log_demuxer_cycles += PRECOMPILE_LOG_DEMUXER_CYCLES; + } + Opcode::FarCall(_) => { + self.statistics.ram_permutation_cycles += FAR_CALL_RAM_CYCLES; + self.statistics.code_decommitter_sorter_cycles += + FAR_CALL_CODE_DECOMMITTER_SORTER_CYCLES; + self.statistics.storage_sorter_cycles += FAR_CALL_STORAGE_SORTER_CYCLES; + } + Opcode::UMA(UMAOpcode::AuxHeapWrite | UMAOpcode::HeapWrite) => { + self.statistics.ram_permutation_cycles += UMA_WRITE_RAM_CYCLES; + } + Opcode::UMA( + UMAOpcode::AuxHeapRead | UMAOpcode::HeapRead | UMAOpcode::FatPointerRead, + ) => { + self.statistics.ram_permutation_cycles += UMA_READ_RAM_CYCLES; + } + Opcode::Invalid(_) => unreachable!(), // invalid opcodes are never executed + }; + } +} + +impl VmTracer for CircuitsTracer { + fn initialize_tracer(&mut self, state: &mut ZkSyncVmState) { + self.last_decommitment_history_entry_checked = Some( + state + .decommittment_processor + .decommitted_code_hashes + .history() + .len(), + ); + + self.last_written_keys_history_entry_checked = + Some(state.storage.written_keys.history().len()); + + self.last_read_keys_history_entry_checked = Some(state.storage.read_keys.history().len()); + + self.last_precompile_inner_entry_checked = Some( + state + .precompiles_processor + .precompile_cycles_history + .inner() + .len(), + ); + } + + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + self.trace_decommitments(state); + self.trace_storage_writes(state); + self.trace_storage_reads(state); + self.trace_precompile_calls(state); + + TracerExecutionStatus::Continue + } +} + +impl CircuitsTracer { + pub(crate) fn new() -> Self { + Self { + statistics: CircuitCycleStatistic::new(), + last_decommitment_history_entry_checked: None, + last_written_keys_history_entry_checked: None, + last_read_keys_history_entry_checked: None, + last_precompile_inner_entry_checked: None, + _phantom_data: Default::default(), + } + } + + fn trace_decommitments(&mut self, state: &ZkSyncVmState) { + let last_decommitment_history_entry_checked = self + .last_decommitment_history_entry_checked + .expect("Value must be set during init"); + let history = state + .decommittment_processor + .decommitted_code_hashes + .history(); + for (_, history_event) in &history[last_decommitment_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + let bytecode_len = state + .decommittment_processor + .known_bytecodes + .inner() + .get(&history_event.key) + .expect("Bytecode must be known at this point") + .len(); + + // Each cycle of `CodeDecommitter` processes 2 words. + // If the number of words in bytecode is odd, then number of cycles must be rounded up. + let decommitter_cycles_used = (bytecode_len + 1) / 2; + self.statistics.code_decommitter_cycles += decommitter_cycles_used as u32; + } + self.last_decommitment_history_entry_checked = Some(history.len()); + } + + fn trace_storage_writes(&mut self, state: &ZkSyncVmState) { + let last_writes_history_entry_checked = self + .last_written_keys_history_entry_checked + .expect("Value must be set during init"); + let history = state.storage.written_keys.history(); + for (_, history_event) in &history[last_writes_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + + self.statistics.storage_application_cycles += STORAGE_WRITE_STORAGE_APPLICATION_CYCLES; + } + self.last_written_keys_history_entry_checked = Some(history.len()); + } + + fn trace_storage_reads(&mut self, state: &ZkSyncVmState) { + let last_reads_history_entry_checked = self + .last_read_keys_history_entry_checked + .expect("Value must be set during init"); + let history = state.storage.read_keys.history(); + for (_, history_event) in &history[last_reads_history_entry_checked..] { + // We assume that only insertions may happen during a single VM inspection. + assert!(history_event.value.is_none()); + + // If the slot is already written to, then we've already taken 2 cycles into account. + if !state + .storage + .written_keys + .inner() + .contains_key(&history_event.key) + { + self.statistics.storage_application_cycles += + STORAGE_READ_STORAGE_APPLICATION_CYCLES; + } + } + self.last_read_keys_history_entry_checked = Some(history.len()); + } + + fn trace_precompile_calls(&mut self, state: &ZkSyncVmState) { + let last_precompile_inner_entry_checked = self + .last_precompile_inner_entry_checked + .expect("Value must be set during init"); + let inner = state + .precompiles_processor + .precompile_cycles_history + .inner(); + for (precompile, cycles) in &inner[last_precompile_inner_entry_checked..] { + match precompile { + PrecompileAddress::Ecrecover => { + self.statistics.ecrecover_cycles += *cycles as u32; + } + PrecompileAddress::SHA256 => { + self.statistics.sha256_cycles += *cycles as u32; + } + PrecompileAddress::Keccak256 => { + self.statistics.keccak256_cycles += *cycles as u32; + } + }; + } + self.last_precompile_inner_entry_checked = Some(inner.len()); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/default_tracers.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/default_tracers.rs new file mode 100644 index 000000000000..05da8f60248a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/default_tracers.rs @@ -0,0 +1,314 @@ +use std::{ + fmt::{Debug, Formatter}, + marker::PhantomData, +}; + +use zk_evm_1_4_1::{ + aux_structures::Timestamp, + tracing::{ + AfterDecodingData, AfterExecutionData, BeforeExecutionData, Tracer, VmLocalStateData, + }, + vm_state::VmLocalState, + witness_trace::DummyTracer, + zkevm_opcode_defs::{decoding::EncodingModeProduction, Opcode, RetOpcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; + +use super::PubdataTracer; +use crate::{ + glue::GlueInto, + interface::{ + tracer::{TracerExecutionStopReason, VmExecutionStopReason}, + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + types::tracer::TracerExecutionStatus, + Halt, VmExecutionMode, + }, + vm_1_4_1::{ + bootloader_state::{utils::apply_l2_block, BootloaderState}, + constants::BOOTLOADER_HEAP_PAGE, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::{ + dispatcher::TracerDispatcher, + utils::{ + computational_gas_price, gas_spent_on_bytecodes_and_long_messages_this_opcode, + print_debug_if_needed, VmHook, + }, + CircuitsTracer, RefundsTracer, ResultTracer, + }, + types::internals::ZkSyncVmState, + VmTracer, + }, +}; + +/// Default tracer for the VM. It manages the other tracers execution and stop the vm when needed. +pub(crate) struct DefaultExecutionTracer { + tx_has_been_processed: bool, + execution_mode: VmExecutionMode, + + pub(crate) gas_spent_on_bytecodes_and_long_messages: u32, + // Amount of gas used during account validation. + pub(crate) computational_gas_used: u32, + // Maximum number of gas that we're allowed to use during account validation. + tx_validation_gas_limit: u32, + in_account_validation: bool, + final_batch_info_requested: bool, + pub(crate) result_tracer: ResultTracer, + // This tracer is designed specifically for calculating refunds. Its separation from the custom tracer + // ensures static dispatch, enhancing performance by avoiding dynamic dispatch overhead. + // Additionally, being an internal tracer, it saves the results directly to `VmResultAndLogs`. + pub(crate) refund_tracer: Option>, + // The pubdata tracer is responsible for inserting the pubdata packing information into the bootloader + // memory at the end of the batch. Its separation from the custom tracer + // ensures static dispatch, enhancing performance by avoiding dynamic dispatch overhead. + pub(crate) pubdata_tracer: Option>, + pub(crate) dispatcher: TracerDispatcher, + ret_from_the_bootloader: Option, + // This tracer tracks what opcodes were executed and calculates how much circuits will be generated. + // It only takes into account circuits that are generated for actual execution. It doesn't + // take into account e.g circuits produced by the initial bootloader memory commitment. + pub(crate) circuits_tracer: CircuitsTracer, + + storage: StoragePtr, + _phantom: PhantomData, +} + +impl DefaultExecutionTracer { + pub(crate) fn new( + computational_gas_limit: u32, + execution_mode: VmExecutionMode, + dispatcher: TracerDispatcher, + storage: StoragePtr, + refund_tracer: Option>, + pubdata_tracer: Option>, + ) -> Self { + Self { + tx_has_been_processed: false, + execution_mode, + gas_spent_on_bytecodes_and_long_messages: 0, + computational_gas_used: 0, + tx_validation_gas_limit: computational_gas_limit, + in_account_validation: false, + final_batch_info_requested: false, + result_tracer: ResultTracer::new(execution_mode), + refund_tracer, + dispatcher, + pubdata_tracer, + ret_from_the_bootloader: None, + circuits_tracer: CircuitsTracer::new(), + storage, + _phantom: PhantomData, + } + } + + pub(crate) fn tx_has_been_processed(&self) -> bool { + self.tx_has_been_processed + } + + pub(crate) fn validation_run_out_of_gas(&self) -> bool { + self.computational_gas_used > self.tx_validation_gas_limit + } + + pub(crate) fn gas_spent_on_pubdata(&self, vm_local_state: &VmLocalState) -> u32 { + self.gas_spent_on_bytecodes_and_long_messages + vm_local_state.spent_pubdata_counter + } + + fn set_fictive_l2_block( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) { + let current_timestamp = Timestamp(state.local_state.timestamp); + let txs_index = bootloader_state.free_tx_index(); + let l2_block = bootloader_state.insert_fictive_l2_block(); + let mut memory = vec![]; + apply_l2_block(&mut memory, l2_block, txs_index); + state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + memory, + current_timestamp.glue_into(), + ); + self.final_batch_info_requested = false; + } + + fn should_stop_execution(&self) -> TracerExecutionStatus { + match self.execution_mode { + VmExecutionMode::OneTx if self.tx_has_been_processed() => { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } + VmExecutionMode::Bootloader if self.ret_from_the_bootloader == Some(RetOpcode::Ok) => { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } + _ => {} + }; + if self.validation_run_out_of_gas() { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::ValidationOutOfGas, + )); + } + TracerExecutionStatus::Continue + } +} + +impl Debug for DefaultExecutionTracer { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DefaultExecutionTracer").finish() + } +} + +/// The default tracer for the VM manages all other tracers. For the sake of optimization, these tracers are statically dispatched. +/// At the same time, the boilerplate for calling these tracers for all tracer calls is quite extensive. +/// This macro is used to reduce the boilerplate. +/// +/// Usage: +/// ``` +/// dispatch_tracers!( +/// self.after_decoding(state, data, memory) +/// ); +/// ``` +/// Whenever a new tracer is added, it should be added to the macro call. +/// +/// The macro passes the function call to all tracers. +macro_rules! dispatch_tracers { + ($self:ident.$function:ident($( $params:expr ),*)) => { + $self.result_tracer.$function($( $params ),*); + $self.dispatcher.$function($( $params ),*); + if let Some(tracer) = &mut $self.refund_tracer { + tracer.$function($( $params ),*); + } + if let Some(tracer) = &mut $self.pubdata_tracer { + tracer.$function($( $params ),*); + } + $self.circuits_tracer.$function($( $params ),*); + }; +} + +impl Tracer for DefaultExecutionTracer { + const CALL_BEFORE_DECODING: bool = false; + const CALL_AFTER_DECODING: bool = true; + const CALL_BEFORE_EXECUTION: bool = true; + const CALL_AFTER_EXECUTION: bool = true; + type SupportedMemory = SimpleMemory; + + fn before_decoding( + &mut self, + _state: VmLocalStateData<'_, 8, EncodingModeProduction>, + _memory: &Self::SupportedMemory, + ) { + } + + fn after_decoding( + &mut self, + state: VmLocalStateData<'_>, + data: AfterDecodingData, + memory: &Self::SupportedMemory, + ) { + dispatch_tracers!(self.after_decoding(state, data, memory)); + } + + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &Self::SupportedMemory, + ) { + if self.in_account_validation { + self.computational_gas_used = self + .computational_gas_used + .saturating_add(computational_gas_price(state, &data)); + } + + let hook = VmHook::from_opcode_memory(&state, &data); + print_debug_if_needed(&hook, &state, memory); + + match hook { + VmHook::TxHasEnded => self.tx_has_been_processed = true, + VmHook::NoValidationEntered => self.in_account_validation = false, + VmHook::AccountValidationEntered => self.in_account_validation = true, + VmHook::FinalBatchInfo => self.final_batch_info_requested = true, + _ => {} + } + + self.gas_spent_on_bytecodes_and_long_messages += + gas_spent_on_bytecodes_and_long_messages_this_opcode(&state, &data); + + dispatch_tracers!(self.before_execution(state, data, memory, self.storage.clone())); + } + + fn after_execution( + &mut self, + state: VmLocalStateData<'_>, + data: AfterExecutionData, + memory: &Self::SupportedMemory, + ) { + if let VmExecutionMode::Bootloader = self.execution_mode { + let (next_opcode, _, _) = zk_evm_1_4_1::vm_state::read_and_decode( + state.vm_local_state, + memory, + &mut DummyTracer, + self, + ); + if current_frame_is_bootloader(state.vm_local_state) { + if let Opcode::Ret(ret) = next_opcode.inner.variant.opcode { + self.ret_from_the_bootloader = Some(ret); + } + } + } + + dispatch_tracers!(self.after_execution(state, data, memory, self.storage.clone())); + } +} + +impl DefaultExecutionTracer { + pub(crate) fn initialize_tracer(&mut self, state: &mut ZkSyncVmState) { + dispatch_tracers!(self.initialize_tracer(state)); + } + + pub(crate) fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + if self.final_batch_info_requested { + self.set_fictive_l2_block(state, bootloader_state) + } + + let mut result = self.result_tracer.finish_cycle(state, bootloader_state); + if let Some(refund_tracer) = &mut self.refund_tracer { + result = refund_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + } + result = self + .dispatcher + .finish_cycle(state, bootloader_state) + .stricter(&result); + if let Some(pubdata_tracer) = &mut self.pubdata_tracer { + result = pubdata_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + } + + result = self + .circuits_tracer + .finish_cycle(state, bootloader_state) + .stricter(&result); + + result.stricter(&self.should_stop_execution()) + } + + pub(crate) fn after_vm_execution( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &BootloaderState, + stop_reason: VmExecutionStopReason, + ) { + dispatch_tracers!(self.after_vm_execution(state, bootloader_state, stop_reason.clone())); + } +} + +fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { + // The current frame is bootloader if the call stack depth is 1. + // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior + // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. + local_state.callstack.inner.len() == 1 +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/dispatcher.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/dispatcher.rs new file mode 100644 index 000000000000..feffd6c20f99 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/dispatcher.rs @@ -0,0 +1,126 @@ +use zk_evm_1_4_1::tracing::{ + AfterDecodingData, AfterExecutionData, BeforeExecutionData, VmLocalStateData, +}; +use zksync_state::{StoragePtr, WriteStorage}; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_1::DynTracer, + tracer::{TracerExecutionStatus, VmExecutionStopReason}, + }, + vm_1_4_1::{ + BootloaderState, HistoryMode, SimpleMemory, TracerPointer, VmTracer, ZkSyncVmState, + }, +}; + +/// Tracer dispatcher is a tracer that can dispatch calls to multiple tracers. +pub struct TracerDispatcher { + tracers: Vec>, +} + +impl TracerDispatcher { + pub fn new(tracers: Vec>) -> Self { + Self { tracers } + } +} + +impl From> for TracerDispatcher { + fn from(value: TracerPointer) -> Self { + Self { + tracers: vec![value], + } + } +} + +impl From>> for TracerDispatcher { + fn from(value: Vec>) -> Self { + Self { tracers: value } + } +} + +impl Default for TracerDispatcher { + fn default() -> Self { + Self { tracers: vec![] } + } +} + +impl DynTracer> for TracerDispatcher { + #[inline(always)] + fn before_decoding(&mut self, _state: VmLocalStateData<'_>, _memory: &SimpleMemory) { + for tracer in self.tracers.iter_mut() { + tracer.before_decoding(_state, _memory); + } + } + + #[inline(always)] + fn after_decoding( + &mut self, + _state: VmLocalStateData<'_>, + _data: AfterDecodingData, + _memory: &SimpleMemory, + ) { + for tracer in self.tracers.iter_mut() { + tracer.after_decoding(_state, _data, _memory); + } + } + + #[inline(always)] + fn before_execution( + &mut self, + _state: VmLocalStateData<'_>, + _data: BeforeExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + for tracer in self.tracers.iter_mut() { + tracer.before_execution(_state, _data, _memory, _storage.clone()); + } + } + + #[inline(always)] + fn after_execution( + &mut self, + _state: VmLocalStateData<'_>, + _data: AfterExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + for tracer in self.tracers.iter_mut() { + tracer.after_execution(_state, _data, _memory, _storage.clone()); + } + } +} + +impl VmTracer for TracerDispatcher { + fn initialize_tracer(&mut self, _state: &mut ZkSyncVmState) { + for tracer in self.tracers.iter_mut() { + tracer.initialize_tracer(_state); + } + } + + /// Run after each vm execution cycle + #[inline(always)] + fn finish_cycle( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + let mut result = TracerExecutionStatus::Continue; + for tracer in self.tracers.iter_mut() { + result = result.stricter(&tracer.finish_cycle(_state, _bootloader_state)); + } + result + } + + /// Run after the vm execution + fn after_vm_execution( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &BootloaderState, + _stop_reason: VmExecutionStopReason, + ) { + for tracer in self.tracers.iter_mut() { + tracer.after_vm_execution(_state, _bootloader_state, _stop_reason.clone()); + } + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/mod.rs new file mode 100644 index 000000000000..fe916e19e8ca --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/mod.rs @@ -0,0 +1,16 @@ +pub(crate) use circuits_tracer::CircuitsTracer; +pub(crate) use default_tracers::DefaultExecutionTracer; +pub(crate) use pubdata_tracer::PubdataTracer; +pub(crate) use refunds::RefundsTracer; +pub(crate) use result_tracer::ResultTracer; + +pub(crate) mod circuits_tracer; +pub(crate) mod default_tracers; +pub(crate) mod pubdata_tracer; +pub(crate) mod refunds; +pub(crate) mod result_tracer; + +pub(crate) mod circuits_capacity; +pub mod dispatcher; +pub(crate) mod traits; +pub(crate) mod utils; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs new file mode 100644 index 000000000000..c69daa0927b5 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs @@ -0,0 +1,238 @@ +use std::marker::PhantomData; + +use zk_evm_1_4_1::{ + aux_structures::Timestamp, + tracing::{BeforeExecutionData, VmLocalStateData}, +}; +use zkevm_test_harness_1_4_1::witness::sort_storage_access::sort_storage_access_queries; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + event::{ + extract_bytecode_publication_requests_from_l1_messenger, + extract_l2tol1logs_from_l1_messenger, extract_long_l2_to_l1_messages, L1MessengerL2ToL1Log, + }, + writes::StateDiffRecord, + AccountTreeId, StorageKey, L1_MESSENGER_ADDRESS, +}; +use zksync_utils::{h256_to_u256, u256_to_bytes_be, u256_to_h256}; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_1::DynTracer, + tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + types::inputs::L1BatchEnv, + VmExecutionMode, + }, + vm_1_4_1::{ + bootloader_state::{utils::apply_pubdata_to_memory, BootloaderState}, + constants::BOOTLOADER_HEAP_PAGE, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::{traits::VmTracer, utils::VmHook}, + types::internals::{PubdataInput, ZkSyncVmState}, + utils::logs::collect_events_and_l1_system_logs_after_timestamp, + StorageOracle, + }, +}; + +/// Tracer responsible for collecting information about refunds. +#[derive(Debug, Clone)] +pub(crate) struct PubdataTracer { + l1_batch_env: L1BatchEnv, + pubdata_info_requested: bool, + execution_mode: VmExecutionMode, + // For testing purposes it might be helpful to supply an exact set of state diffs to be provided + // to the L1Messenger. + enforced_state_diffs: Option>, + _phantom_data: PhantomData, +} + +impl PubdataTracer { + pub(crate) fn new(l1_batch_env: L1BatchEnv, execution_mode: VmExecutionMode) -> Self { + Self { + l1_batch_env, + pubdata_info_requested: false, + execution_mode, + enforced_state_diffs: None, + _phantom_data: Default::default(), + } + } + + // Creates the pubdata tracer with constant state diffs. + // To be used in tests only. + #[cfg(test)] + pub(crate) fn new_with_forced_state_diffs( + l1_batch_env: L1BatchEnv, + execution_mode: VmExecutionMode, + forced_state_diffs: Vec, + ) -> Self { + Self { + l1_batch_env, + pubdata_info_requested: false, + execution_mode, + enforced_state_diffs: Some(forced_state_diffs), + _phantom_data: Default::default(), + } + } + + // Packs part of L1 Messenger total pubdata that corresponds to + // `L2toL1Logs` sent in the block + fn get_total_user_logs( + &self, + state: &ZkSyncVmState, + ) -> Vec { + let (all_generated_events, _) = collect_events_and_l1_system_logs_after_timestamp( + state, + &self.l1_batch_env, + Timestamp(0), + ); + extract_l2tol1logs_from_l1_messenger(&all_generated_events) + } + + // Packs part of L1 Messenger total pubdata that corresponds to + // Messages sent in the block + fn get_total_l1_messenger_messages( + &self, + state: &ZkSyncVmState, + ) -> Vec> { + let (all_generated_events, _) = collect_events_and_l1_system_logs_after_timestamp( + state, + &self.l1_batch_env, + Timestamp(0), + ); + + extract_long_l2_to_l1_messages(&all_generated_events) + } + + // Packs part of L1 Messenger total pubdata that corresponds to + // Bytecodes needed to be published on L1 + fn get_total_published_bytecodes( + &self, + state: &ZkSyncVmState, + ) -> Vec> { + let (all_generated_events, _) = collect_events_and_l1_system_logs_after_timestamp( + state, + &self.l1_batch_env, + Timestamp(0), + ); + + let bytecode_publication_requests = + extract_bytecode_publication_requests_from_l1_messenger(&all_generated_events); + + bytecode_publication_requests + .iter() + .map(|bytecode_publication_request| { + state + .decommittment_processor + .known_bytecodes + .inner() + .get(&h256_to_u256(bytecode_publication_request.bytecode_hash)) + .unwrap() + .iter() + .flat_map(u256_to_bytes_be) + .collect() + }) + .collect() + } + + // Packs part of L1Messenger total pubdata that corresponds to + // State diffs needed to be published on L1 + fn get_state_diffs( + &self, + storage: &StorageOracle, + ) -> Vec { + if let Some(enforced_state_diffs) = &self.enforced_state_diffs { + return enforced_state_diffs.clone(); + } + + sort_storage_access_queries( + storage + .storage_log_queries_after_timestamp(Timestamp(0)) + .iter() + .map(|log| &log.log_query), + ) + .1 + .into_iter() + .filter(|log| log.rw_flag) + .filter(|log| log.read_value != log.written_value) + .filter(|log| log.address != L1_MESSENGER_ADDRESS) + .map(|log| StateDiffRecord { + address: log.address, + key: log.key, + derived_key: log.derive_final_address(), + enumeration_index: storage + .storage + .get_ptr() + .borrow_mut() + .get_enumeration_index(&StorageKey::new( + AccountTreeId::new(log.address), + u256_to_h256(log.key), + )) + .unwrap_or_default(), + initial_value: log.read_value, + final_value: log.written_value, + }) + .collect() + } + + fn build_pubdata_input(&self, state: &ZkSyncVmState) -> PubdataInput { + PubdataInput { + user_logs: self.get_total_user_logs(state), + l2_to_l1_messages: self.get_total_l1_messenger_messages(state), + published_bytecodes: self.get_total_published_bytecodes(state), + state_diffs: self.get_state_diffs(&state.storage), + } + } +} + +impl DynTracer> for PubdataTracer { + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + _memory: &SimpleMemory, + _storage: StoragePtr, + ) { + let hook = VmHook::from_opcode_memory(&state, &data); + if let VmHook::PubdataRequested = hook { + self.pubdata_info_requested = true; + } + } +} + +impl VmTracer for PubdataTracer { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + if !matches!(self.execution_mode, VmExecutionMode::Batch) { + // We do not provide the pubdata when executing the block tip or a single transaction + if self.pubdata_info_requested { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } else { + return TracerExecutionStatus::Continue; + } + } + + if self.pubdata_info_requested { + let pubdata_input = self.build_pubdata_input(state); + + // Save the pubdata for the future initial bootloader memory building + bootloader_state.set_pubdata_input(pubdata_input.clone()); + + // Apply the pubdata to the current memory + let mut memory_to_apply = vec![]; + + apply_pubdata_to_memory(&mut memory_to_apply, pubdata_input); + state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + memory_to_apply, + Timestamp(state.local_state.timestamp), + ); + + self.pubdata_info_requested = false; + } + + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs new file mode 100644 index 000000000000..9fba21c42078 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs @@ -0,0 +1,361 @@ +use std::marker::PhantomData; + +use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics}; +use zk_evm_1_4_1::{ + aux_structures::Timestamp, + tracing::{BeforeExecutionData, VmLocalStateData}, + vm_state::VmLocalState, + zkevm_opcode_defs::system_params::L1_MESSAGE_PUBDATA_BYTES, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::{PUBLISH_BYTECODE_OVERHEAD, SYSTEM_CONTEXT_ADDRESS}; +use zksync_types::{ + event::{extract_long_l2_to_l1_messages, extract_published_bytecodes}, + l2_to_l1_log::L2ToL1Log, + L1BatchNumber, H256, U256, +}; +use zksync_utils::{bytecode::bytecode_len_in_bytes, ceil_div_u256, u256_to_h256}; + +use crate::{ + interface::{ + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, types::tracer::TracerExecutionStatus, + L1BatchEnv, Refunds, + }, + vm_1_4_1::{ + bootloader_state::BootloaderState, + constants::{BOOTLOADER_HEAP_PAGE, OPERATOR_REFUNDS_OFFSET, TX_GAS_LIMIT_OFFSET}, + old_vm::{events::merge_events, history_recorder::HistoryMode, memory::SimpleMemory}, + tracers::{ + traits::VmTracer, + utils::{ + gas_spent_on_bytecodes_and_long_messages_this_opcode, get_vm_hook_params, VmHook, + }, + }, + types::internals::ZkSyncVmState, + utils::fee::get_batch_base_fee, + }, +}; + +/// Tracer responsible for collecting information about refunds. +#[derive(Debug, Clone)] +pub(crate) struct RefundsTracer { + // Some(x) means that the bootloader has asked the operator + // to provide the refund the user, where `x` is the refund proposed + // by the bootloader itself. + pending_operator_refund: Option, + refund_gas: u32, + operator_refund: Option, + timestamp_initial: Timestamp, + timestamp_before_cycle: Timestamp, + gas_remaining_before: u32, + spent_pubdata_counter_before: u32, + gas_spent_on_bytecodes_and_long_messages: u32, + l1_batch: L1BatchEnv, + pubdata_published: u32, + _phantom: PhantomData, +} + +impl RefundsTracer { + pub(crate) fn new(l1_batch: L1BatchEnv) -> Self { + Self { + pending_operator_refund: None, + refund_gas: 0, + operator_refund: None, + timestamp_initial: Timestamp(0), + timestamp_before_cycle: Timestamp(0), + gas_remaining_before: 0, + spent_pubdata_counter_before: 0, + gas_spent_on_bytecodes_and_long_messages: 0, + l1_batch, + pubdata_published: 0, + _phantom: PhantomData, + } + } +} + +impl RefundsTracer { + fn requested_refund(&self) -> Option { + self.pending_operator_refund + } + + fn set_refund_as_done(&mut self) { + self.pending_operator_refund = None; + } + + fn block_overhead_refund(&mut self) -> u32 { + 0 + } + + pub(crate) fn get_refunds(&self) -> Refunds { + Refunds { + gas_refunded: self.refund_gas, + operator_suggested_refund: self.operator_refund.unwrap_or_default(), + } + } + + pub(crate) fn tx_body_refund( + &self, + bootloader_refund: u32, + gas_spent_on_pubdata: u32, + tx_gas_limit: u32, + current_ergs_per_pubdata_byte: u32, + pubdata_published: u32, + tx_hash: H256, + ) -> u32 { + let total_gas_spent = tx_gas_limit - bootloader_refund; + + let gas_spent_on_computation = total_gas_spent + .checked_sub(gas_spent_on_pubdata) + .unwrap_or_else(|| { + tracing::error!( + "Gas spent on pubdata is greater than total gas spent. On pubdata: {}, total: {}", + gas_spent_on_pubdata, + total_gas_spent + ); + 0 + }); + + // For now, bootloader charges only for base fee. + let effective_gas_price = get_batch_base_fee(&self.l1_batch); + + let bootloader_eth_price_per_pubdata_byte = + U256::from(effective_gas_price) * U256::from(current_ergs_per_pubdata_byte); + + let fair_eth_price_per_pubdata_byte = + U256::from(self.l1_batch.fee_input.fair_pubdata_price()); + + // For now, L1 originated transactions are allowed to pay less than fair fee per pubdata, + // so we should take it into account. + let eth_price_per_pubdata_byte_for_calculation = std::cmp::min( + bootloader_eth_price_per_pubdata_byte, + fair_eth_price_per_pubdata_byte, + ); + + let fair_fee_eth = U256::from(gas_spent_on_computation) + * U256::from(self.l1_batch.fee_input.fair_l2_gas_price()) + + U256::from(pubdata_published) * eth_price_per_pubdata_byte_for_calculation; + let pre_paid_eth = U256::from(tx_gas_limit) * U256::from(effective_gas_price); + let refund_eth = pre_paid_eth.checked_sub(fair_fee_eth).unwrap_or_else(|| { + tracing::error!( + "Fair fee is greater than pre paid. Fair fee: {} wei, pre paid: {} wei", + fair_fee_eth, + pre_paid_eth + ); + U256::zero() + }); + + tracing::trace!( + "Fee benchmark for transaction with hash {}", + hex::encode(tx_hash.as_bytes()) + ); + tracing::trace!("Gas Limit: {}", tx_gas_limit); + tracing::trace!("Gas spent on computation: {}", gas_spent_on_computation); + tracing::trace!("Gas spent on pubdata: {}", gas_spent_on_pubdata); + tracing::trace!("Pubdata published: {}", pubdata_published); + + ceil_div_u256(refund_eth, effective_gas_price.into()).as_u32() + } + + pub(crate) fn gas_spent_on_pubdata(&self, vm_local_state: &VmLocalState) -> u32 { + self.gas_spent_on_bytecodes_and_long_messages + vm_local_state.spent_pubdata_counter + } + + pub(crate) fn pubdata_published(&self) -> u32 { + self.pubdata_published + } +} + +impl DynTracer> for RefundsTracer { + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + _storage: StoragePtr, + ) { + self.timestamp_before_cycle = Timestamp(state.vm_local_state.timestamp); + let hook = VmHook::from_opcode_memory(&state, &data); + match hook { + VmHook::NotifyAboutRefund => self.refund_gas = get_vm_hook_params(memory)[0].as_u32(), + VmHook::AskOperatorForRefund => { + self.pending_operator_refund = Some(get_vm_hook_params(memory)[0].as_u32()) + } + _ => {} + } + + self.gas_spent_on_bytecodes_and_long_messages += + gas_spent_on_bytecodes_and_long_messages_this_opcode(&state, &data); + } +} + +impl VmTracer for RefundsTracer { + fn initialize_tracer(&mut self, state: &mut ZkSyncVmState) { + self.timestamp_initial = Timestamp(state.local_state.timestamp); + self.gas_remaining_before = state.local_state.callstack.current.ergs_remaining; + self.spent_pubdata_counter_before = state.local_state.spent_pubdata_counter; + } + + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelValue, EncodeLabelSet)] + #[metrics(label = "type", rename_all = "snake_case")] + enum RefundType { + Bootloader, + Operator, + } + + const PERCENT_BUCKETS: Buckets = Buckets::values(&[ + 5.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 120.0, + ]); + + #[derive(Debug, Metrics)] + #[metrics(prefix = "vm")] + struct RefundMetrics { + #[metrics(buckets = PERCENT_BUCKETS)] + refund: Family>, + #[metrics(buckets = PERCENT_BUCKETS)] + refund_diff: Histogram, + } + + #[vise::register] + static METRICS: vise::Global = vise::Global::new(); + + // This means that the bootloader has informed the system (usually via `VMHooks`) - that some gas + // should be refunded back (see `askOperatorForRefund` in `bootloader.yul` for details). + if let Some(bootloader_refund) = self.requested_refund() { + assert!( + self.operator_refund.is_none(), + "Operator was asked for refund two times" + ); + let gas_spent_on_pubdata = + self.gas_spent_on_pubdata(&state.local_state) - self.spent_pubdata_counter_before; + + let current_tx_index = bootloader_state.current_tx(); + let tx_description_offset = + bootloader_state.get_tx_description_offset(current_tx_index); + let tx_gas_limit = state + .memory + .read_slot( + BOOTLOADER_HEAP_PAGE as usize, + tx_description_offset + TX_GAS_LIMIT_OFFSET, + ) + .value + .as_u32(); + + let used_published_storage_slots = state + .storage + .save_paid_changes(Timestamp(state.local_state.timestamp)); + + let pubdata_published = pubdata_published( + state, + used_published_storage_slots, + self.timestamp_initial, + self.l1_batch.number, + ); + + self.pubdata_published = pubdata_published; + let current_ergs_per_pubdata_byte = state.local_state.current_ergs_per_pubdata_byte; + + let tx_body_refund = self.tx_body_refund( + bootloader_refund, + gas_spent_on_pubdata, + tx_gas_limit, + current_ergs_per_pubdata_byte, + pubdata_published, + bootloader_state.last_l2_block().txs.last().unwrap().hash, + ); + + if tx_body_refund < bootloader_refund { + tracing::error!( + "Suggested tx body refund is less than bootloader refund. Tx body refund: {tx_body_refund}, \ + bootloader refund: {bootloader_refund}" + ); + } + + let refund_to_propose = tx_body_refund + self.block_overhead_refund(); + + let refund_slot = OPERATOR_REFUNDS_OFFSET + current_tx_index; + + // Writing the refund into memory + state.memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + vec![(refund_slot, refund_to_propose.into())], + self.timestamp_before_cycle, + ); + + bootloader_state.set_refund_for_current_tx(refund_to_propose); + self.operator_refund = Some(refund_to_propose); + self.set_refund_as_done(); + + if tx_gas_limit < bootloader_refund { + tracing::error!( + "Tx gas limit is less than bootloader refund. Tx gas limit: {tx_gas_limit}, \ + bootloader refund: {bootloader_refund}" + ); + } + if tx_gas_limit < refund_to_propose { + tracing::error!( + "Tx gas limit is less than operator refund. Tx gas limit: {tx_gas_limit}, \ + operator refund: {refund_to_propose}" + ); + } + + METRICS.refund[&RefundType::Bootloader] + .observe(bootloader_refund as f64 / tx_gas_limit as f64 * 100.0); + METRICS.refund[&RefundType::Operator] + .observe(refund_to_propose as f64 / tx_gas_limit as f64 * 100.0); + let refund_diff = + (refund_to_propose as f64 - bootloader_refund as f64) / tx_gas_limit as f64 * 100.0; + METRICS.refund_diff.observe(refund_diff); + } + TracerExecutionStatus::Continue + } +} + +/// Returns the given transactions' gas limit - by reading it directly from the VM memory. +pub(crate) fn pubdata_published( + state: &ZkSyncVmState, + storage_writes_pubdata_published: u32, + from_timestamp: Timestamp, + batch_number: L1BatchNumber, +) -> u32 { + let (raw_events, l1_messages) = state + .event_sink + .get_events_and_l2_l1_logs_after_timestamp(from_timestamp); + let events: Vec<_> = merge_events(raw_events) + .into_iter() + .map(|e| e.into_vm_event(batch_number)) + .collect(); + // For the first transaction in L1 batch there may be (it depends on the execution mode) an L2->L1 log + // that is sent by `SystemContext` in `setNewBlock`. It's a part of the L1 batch pubdata overhead and not the transaction itself. + let l2_l1_logs_bytes = (l1_messages + .into_iter() + .map(|log| L2ToL1Log { + shard_id: log.shard_id, + is_service: log.is_first, + tx_number_in_block: log.tx_number_in_block, + sender: log.address, + key: u256_to_h256(log.key), + value: u256_to_h256(log.value), + }) + .filter(|log| log.sender != SYSTEM_CONTEXT_ADDRESS) + .count() as u32) + * L1_MESSAGE_PUBDATA_BYTES; + let l2_l1_long_messages_bytes: u32 = extract_long_l2_to_l1_messages(&events) + .iter() + .map(|event| event.len() as u32) + .sum(); + + let published_bytecode_bytes: u32 = extract_published_bytecodes(&events) + .iter() + .map(|bytecodehash| bytecode_len_in_bytes(*bytecodehash) as u32 + PUBLISH_BYTECODE_OVERHEAD) + .sum(); + + storage_writes_pubdata_published + + l2_l1_logs_bytes + + l2_l1_long_messages_bytes + + published_bytecode_bytes +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/result_tracer.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/result_tracer.rs new file mode 100644 index 000000000000..a0090393b889 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/result_tracer.rs @@ -0,0 +1,246 @@ +use std::marker::PhantomData; + +use zk_evm_1_4_1::{ + tracing::{AfterDecodingData, BeforeExecutionData, VmLocalStateData}, + vm_state::{ErrorFlags, VmLocalState}, + zkevm_opcode_defs::FatPointer, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::U256; + +use crate::{ + interface::{ + tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + types::tracer::TracerExecutionStopReason, ExecutionResult, Halt, TxRevertReason, + VmExecutionMode, VmRevertReason, + }, + vm_1_4_1::{ + constants::{BOOTLOADER_HEAP_PAGE, RESULT_SUCCESS_FIRST_SLOT}, + old_vm::utils::{vm_may_have_ended_inner, VmExecutionResult}, + tracers::{ + traits::VmTracer, + utils::{get_vm_hook_params, read_pointer, VmHook}, + }, + types::internals::ZkSyncVmState, + BootloaderState, HistoryMode, SimpleMemory, + }, +}; + +#[derive(Debug, Clone)] +enum Result { + Error { error_reason: VmRevertReason }, + Success { return_data: Vec }, + Halt { reason: Halt }, +} + +/// Tracer responsible for handling the VM execution result. +#[derive(Debug, Clone)] +pub(crate) struct ResultTracer { + result: Option, + bootloader_out_of_gas: bool, + execution_mode: VmExecutionMode, + _phantom: PhantomData, +} + +impl ResultTracer { + pub(crate) fn new(execution_mode: VmExecutionMode) -> Self { + Self { + result: None, + bootloader_out_of_gas: false, + execution_mode, + _phantom: PhantomData, + } + } +} + +fn current_frame_is_bootloader(local_state: &VmLocalState) -> bool { + // The current frame is bootloader if the call stack depth is 1. + // Some of the near calls inside the bootloader can be out of gas, which is totally normal behavior + // and it shouldn't result in `is_bootloader_out_of_gas` becoming true. + local_state.callstack.inner.len() == 1 +} + +impl DynTracer> for ResultTracer { + fn after_decoding( + &mut self, + state: VmLocalStateData<'_>, + data: AfterDecodingData, + _memory: &SimpleMemory, + ) { + // We should check not only for the `NOT_ENOUGH_ERGS` flag but if the current frame is bootloader too. + if current_frame_is_bootloader(state.vm_local_state) + && data + .error_flags_accumulated + .contains(ErrorFlags::NOT_ENOUGH_ERGS) + { + self.bootloader_out_of_gas = true; + } + } + + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + _storage: StoragePtr, + ) { + let hook = VmHook::from_opcode_memory(&state, &data); + if let VmHook::ExecutionResult = hook { + let vm_hook_params = get_vm_hook_params(memory); + let success = vm_hook_params[0]; + let returndata_ptr = FatPointer::from_u256(vm_hook_params[1]); + let returndata = read_pointer(memory, returndata_ptr); + if success == U256::zero() { + self.result = Some(Result::Error { + // Tx has reverted, without bootloader error, we can simply parse the revert reason + error_reason: (VmRevertReason::from(returndata.as_slice())), + }); + } else { + self.result = Some(Result::Success { + return_data: returndata, + }); + } + } + } +} + +impl VmTracer for ResultTracer { + fn after_vm_execution( + &mut self, + state: &mut ZkSyncVmState, + bootloader_state: &BootloaderState, + stop_reason: VmExecutionStopReason, + ) { + match stop_reason { + // Vm has finished execution, we need to check the result of it + VmExecutionStopReason::VmFinished => { + self.vm_finished_execution(state); + } + // One of the tracers above has requested to stop the execution. + // If it was the correct stop we already have the result, + // otherwise it can be out of gas error + VmExecutionStopReason::TracerRequestedStop(reason) => { + match self.execution_mode { + VmExecutionMode::OneTx => { + self.vm_stopped_execution(state, bootloader_state, reason) + } + VmExecutionMode::Batch => self.vm_finished_execution(state), + VmExecutionMode::Bootloader => self.vm_finished_execution(state), + }; + } + } + } +} + +impl ResultTracer { + fn vm_finished_execution(&mut self, state: &ZkSyncVmState) { + let Some(result) = vm_may_have_ended_inner(state) else { + // The VM has finished execution, but the result is not yet available. + self.result = Some(Result::Success { + return_data: vec![], + }); + return; + }; + + // Check it's not inside tx + match result { + VmExecutionResult::Ok(output) => { + self.result = Some(Result::Success { + return_data: output, + }); + } + VmExecutionResult::Revert(output) => { + // Unlike `VmHook::ExecutionResult`, vm has completely finished and returned not only the revert reason, + // but with bytecode, which represents the type of error from the bootloader side + let revert_reason = TxRevertReason::parse_error(&output); + + match revert_reason { + TxRevertReason::TxReverted(reason) => { + self.result = Some(Result::Error { + error_reason: reason, + }); + } + TxRevertReason::Halt(halt) => { + self.result = Some(Result::Halt { reason: halt }); + } + }; + } + VmExecutionResult::Panic => { + if self.bootloader_out_of_gas { + self.result = Some(Result::Halt { + reason: Halt::BootloaderOutOfGas, + }); + } else { + self.result = Some(Result::Halt { + reason: Halt::VMPanic, + }); + } + } + VmExecutionResult::MostLikelyDidNotFinish(_, _) => { + unreachable!() + } + } + } + + fn vm_stopped_execution( + &mut self, + state: &ZkSyncVmState, + bootloader_state: &BootloaderState, + reason: TracerExecutionStopReason, + ) { + if let TracerExecutionStopReason::Abort(halt) = reason { + self.result = Some(Result::Halt { reason: halt }); + return; + } + + if self.bootloader_out_of_gas { + self.result = Some(Result::Halt { + reason: Halt::BootloaderOutOfGas, + }); + } else { + if self.result.is_some() { + return; + } + + let has_failed = tx_has_failed(state, bootloader_state.current_tx() as u32); + if has_failed { + self.result = Some(Result::Error { + error_reason: VmRevertReason::General { + msg: "Transaction reverted with empty reason. Possibly out of gas" + .to_string(), + data: vec![], + }, + }); + } else { + self.result = Some(self.result.clone().unwrap_or(Result::Success { + return_data: vec![], + })); + } + } + } + + pub(crate) fn into_result(self) -> ExecutionResult { + match self.result.unwrap() { + Result::Error { error_reason } => ExecutionResult::Revert { + output: error_reason, + }, + Result::Success { return_data } => ExecutionResult::Success { + output: return_data, + }, + Result::Halt { reason } => ExecutionResult::Halt { reason }, + } + } +} + +pub(crate) fn tx_has_failed( + state: &ZkSyncVmState, + tx_id: u32, +) -> bool { + let mem_slot = RESULT_SUCCESS_FIRST_SLOT + tx_id; + let mem_value = state + .memory + .read_slot(BOOTLOADER_HEAP_PAGE as usize, mem_slot as usize) + .value; + + mem_value == U256::zero() +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/traits.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/traits.rs new file mode 100644 index 000000000000..d738c9484fdc --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/traits.rs @@ -0,0 +1,47 @@ +use zksync_state::WriteStorage; + +use crate::{ + interface::{ + dyn_tracers::vm_1_4_1::DynTracer, + tracer::{TracerExecutionStatus, VmExecutionStopReason}, + }, + vm_1_4_1::{ + bootloader_state::BootloaderState, + old_vm::{history_recorder::HistoryMode, memory::SimpleMemory}, + types::internals::ZkSyncVmState, + }, +}; + +pub type TracerPointer = Box>; + +/// Run tracer for collecting data during the vm execution cycles +pub trait VmTracer: DynTracer> { + /// Initialize the tracer before the vm execution + fn initialize_tracer(&mut self, _state: &mut ZkSyncVmState) {} + /// Run after each vm execution cycle + fn finish_cycle( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + TracerExecutionStatus::Continue + } + /// Run after the vm execution + fn after_vm_execution( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &BootloaderState, + _stop_reason: VmExecutionStopReason, + ) { + } +} + +pub trait ToTracerPointer { + fn into_tracer_pointer(self) -> TracerPointer; +} + +impl + 'static> ToTracerPointer for T { + fn into_tracer_pointer(self) -> TracerPointer { + Box::new(self) + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/utils.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/utils.rs new file mode 100644 index 000000000000..86becfbbc96b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/utils.rs @@ -0,0 +1,225 @@ +use zk_evm_1_4_1::{ + aux_structures::MemoryPage, + tracing::{BeforeExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ + FarCallABI, FarCallForwardPageType, FatPointer, LogOpcode, Opcode, UMAOpcode, + }, +}; +use zksync_system_constants::{ + ECRECOVER_PRECOMPILE_ADDRESS, KECCAK256_PRECOMPILE_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS, + L1_MESSENGER_ADDRESS, SHA256_PRECOMPILE_ADDRESS, +}; +use zksync_types::U256; +use zksync_utils::u256_to_h256; + +use crate::vm_1_4_1::{ + constants::{ + BOOTLOADER_HEAP_PAGE, VM_HOOK_PARAMS_COUNT, VM_HOOK_PARAMS_START_POSITION, VM_HOOK_POSITION, + }, + old_vm::{ + history_recorder::HistoryMode, + memory::SimpleMemory, + utils::{aux_heap_page_from_base, heap_page_from_base}, + }, +}; + +#[derive(Clone, Debug, Copy)] +pub(crate) enum VmHook { + AccountValidationEntered, + PaymasterValidationEntered, + NoValidationEntered, + ValidationStepEndeded, + TxHasEnded, + DebugLog, + DebugReturnData, + NoHook, + NearCallCatch, + AskOperatorForRefund, + NotifyAboutRefund, + ExecutionResult, + FinalBatchInfo, + // Hook used to signal that the final pubdata for a batch is requested. + PubdataRequested, +} + +impl VmHook { + pub(crate) fn from_opcode_memory( + state: &VmLocalStateData<'_>, + data: &BeforeExecutionData, + ) -> Self { + let opcode_variant = data.opcode.variant; + let heap_page = + heap_page_from_base(state.vm_local_state.callstack.current.base_memory_page).0; + + let src0_value = data.src0_value.value; + + let fat_ptr = FatPointer::from_u256(src0_value); + + let value = data.src1_value.value; + + // Only `UMA` opcodes in the bootloader serve for vm hooks + if !matches!(opcode_variant.opcode, Opcode::UMA(UMAOpcode::HeapWrite)) + || heap_page != BOOTLOADER_HEAP_PAGE + || fat_ptr.offset != VM_HOOK_POSITION * 32 + { + return Self::NoHook; + } + + match value.as_u32() { + 0 => Self::AccountValidationEntered, + 1 => Self::PaymasterValidationEntered, + 2 => Self::NoValidationEntered, + 3 => Self::ValidationStepEndeded, + 4 => Self::TxHasEnded, + 5 => Self::DebugLog, + 6 => Self::DebugReturnData, + 7 => Self::NearCallCatch, + 8 => Self::AskOperatorForRefund, + 9 => Self::NotifyAboutRefund, + 10 => Self::ExecutionResult, + 11 => Self::FinalBatchInfo, + 12 => Self::PubdataRequested, + _ => panic!("Unknown hook: {}", value.as_u32()), + } + } +} + +pub(crate) fn get_debug_log( + state: &VmLocalStateData<'_>, + memory: &SimpleMemory, +) -> String { + let vm_hook_params: Vec<_> = get_vm_hook_params(memory) + .into_iter() + .map(u256_to_h256) + .collect(); + let msg = vm_hook_params[0].as_bytes().to_vec(); + let data = vm_hook_params[1].as_bytes().to_vec(); + + let msg = String::from_utf8(msg).expect("Invalid debug message"); + let data = U256::from_big_endian(&data); + + // For long data, it is better to use hex-encoding for greater readability + let data_str = if data > U256::from(u64::max_value()) { + let mut bytes = [0u8; 32]; + data.to_big_endian(&mut bytes); + format!("0x{}", hex::encode(bytes)) + } else { + data.to_string() + }; + + let tx_id = state.vm_local_state.tx_number_in_block; + + format!("Bootloader transaction {}: {} {}", tx_id, msg, data_str) +} + +/// Reads the memory slice represented by the fat pointer. +/// Note, that the fat pointer must point to the accessible memory (i.e. not cleared up yet). +pub(crate) fn read_pointer( + memory: &SimpleMemory, + pointer: FatPointer, +) -> Vec { + let FatPointer { + offset, + length, + start, + memory_page, + } = pointer; + + // The actual bounds of the returndata ptr is [start+offset..start+length] + let mem_region_start = start + offset; + let mem_region_length = length - offset; + + memory.read_unaligned_bytes( + memory_page as usize, + mem_region_start as usize, + mem_region_length as usize, + ) +} + +/// Outputs the returndata for the latest call. +/// This is usually used to output the revert reason. +pub(crate) fn get_debug_returndata(memory: &SimpleMemory) -> String { + let vm_hook_params: Vec<_> = get_vm_hook_params(memory); + let returndata_ptr = FatPointer::from_u256(vm_hook_params[0]); + let returndata = read_pointer(memory, returndata_ptr); + + format!("0x{}", hex::encode(returndata)) +} + +/// Accepts a vm hook and, if it requires to output some debug log, outputs it. +pub(crate) fn print_debug_if_needed( + hook: &VmHook, + state: &VmLocalStateData<'_>, + memory: &SimpleMemory, +) { + let log = match hook { + VmHook::DebugLog => get_debug_log(state, memory), + VmHook::DebugReturnData => get_debug_returndata(memory), + _ => return, + }; + + tracing::trace!("{}", log); +} + +pub(crate) fn computational_gas_price( + state: VmLocalStateData<'_>, + data: &BeforeExecutionData, +) -> u32 { + // We calculate computational gas used as a raw price for opcode plus cost for precompiles. + // This calculation is incomplete as it misses decommitment and memory growth costs. + // To calculate decommitment cost we need an access to decommitter oracle which is missing in tracer now. + // Memory growth calculation is complex and it will require different logic for different opcodes (`FarCall`, `Ret`, `UMA`). + let base_price = data.opcode.inner.variant.ergs_price(); + let precompile_price = match data.opcode.variant.opcode { + Opcode::Log(LogOpcode::PrecompileCall) => { + let address = state.vm_local_state.callstack.current.this_address; + + if address == KECCAK256_PRECOMPILE_ADDRESS + || address == SHA256_PRECOMPILE_ADDRESS + || address == ECRECOVER_PRECOMPILE_ADDRESS + { + data.src1_value.value.low_u32() + } else { + 0 + } + } + _ => 0, + }; + base_price + precompile_price +} + +pub(crate) fn gas_spent_on_bytecodes_and_long_messages_this_opcode( + state: &VmLocalStateData<'_>, + data: &BeforeExecutionData, +) -> u32 { + if data.opcode.variant.opcode == Opcode::Log(LogOpcode::PrecompileCall) { + let current_stack = state.vm_local_state.callstack.get_current_stack(); + // Trace for precompile calls from `KNOWN_CODES_STORAGE_ADDRESS` and `L1_MESSENGER_ADDRESS` that burn some gas. + // Note, that if there is less gas left than requested to burn it will be burnt anyway. + if current_stack.this_address == KNOWN_CODES_STORAGE_ADDRESS + || current_stack.this_address == L1_MESSENGER_ADDRESS + { + std::cmp::min(data.src1_value.value.as_u32(), current_stack.ergs_remaining) + } else { + 0 + } + } else { + 0 + } +} + +pub(crate) fn get_calldata_page_via_abi(far_call_abi: &FarCallABI, base_page: MemoryPage) -> u32 { + match far_call_abi.forwarding_mode { + FarCallForwardPageType::ForwardFatPointer => { + far_call_abi.memory_quasi_fat_pointer.memory_page + } + FarCallForwardPageType::UseAuxHeap => aux_heap_page_from_base(base_page).0, + FarCallForwardPageType::UseHeap => heap_page_from_base(base_page).0, + } +} +pub(crate) fn get_vm_hook_params(memory: &SimpleMemory) -> Vec { + memory.dump_page_content_as_u256_words( + BOOTLOADER_HEAP_PAGE, + VM_HOOK_PARAMS_START_POSITION..VM_HOOK_PARAMS_START_POSITION + VM_HOOK_PARAMS_COUNT, + ) +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/internals/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/mod.rs new file mode 100644 index 000000000000..7dc60ec5b0fb --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/mod.rs @@ -0,0 +1,9 @@ +pub(crate) use pubdata::PubdataInput; +pub(crate) use snapshot::VmSnapshot; +pub(crate) use transaction_data::TransactionData; +pub(crate) use vm_state::new_vm_state; +pub use vm_state::ZkSyncVmState; +mod pubdata; +mod snapshot; +mod transaction_data; +mod vm_state; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/internals/pubdata.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/pubdata.rs new file mode 100644 index 000000000000..38489a6c8e92 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/pubdata.rs @@ -0,0 +1,124 @@ +use zksync_types::{ + event::L1MessengerL2ToL1Log, + writes::{compress_state_diffs, StateDiffRecord}, +}; + +/// Struct based on which the pubdata blob is formed +#[derive(Debug, Clone, Default)] +pub(crate) struct PubdataInput { + pub(crate) user_logs: Vec, + pub(crate) l2_to_l1_messages: Vec>, + pub(crate) published_bytecodes: Vec>, + pub(crate) state_diffs: Vec, +} + +impl PubdataInput { + pub(crate) fn build_pubdata(self, with_uncompressed_state_diffs: bool) -> Vec { + let mut l1_messenger_pubdata = vec![]; + + let PubdataInput { + user_logs, + l2_to_l1_messages, + published_bytecodes, + state_diffs, + } = self; + + // Encoding user L2->L1 logs. + // Format: `[(numberOfL2ToL1Logs as u32) || l2tol1logs[1] || ... || l2tol1logs[n]]` + l1_messenger_pubdata.extend((user_logs.len() as u32).to_be_bytes()); + for l2tol1log in user_logs { + l1_messenger_pubdata.extend(l2tol1log.packed_encoding()); + } + + // Encoding L2->L1 messages + // Format: `[(numberOfMessages as u32) || (messages[1].len() as u32) || messages[1] || ... || (messages[n].len() as u32) || messages[n]]` + l1_messenger_pubdata.extend((l2_to_l1_messages.len() as u32).to_be_bytes()); + for message in l2_to_l1_messages { + l1_messenger_pubdata.extend((message.len() as u32).to_be_bytes()); + l1_messenger_pubdata.extend(message); + } + + // Encoding bytecodes + // Format: `[(numberOfBytecodes as u32) || (bytecodes[1].len() as u32) || bytecodes[1] || ... || (bytecodes[n].len() as u32) || bytecodes[n]]` + l1_messenger_pubdata.extend((published_bytecodes.len() as u32).to_be_bytes()); + for bytecode in published_bytecodes { + l1_messenger_pubdata.extend((bytecode.len() as u32).to_be_bytes()); + l1_messenger_pubdata.extend(bytecode); + } + + // Encoding state diffs + // Format: `[size of compressed state diffs u32 || compressed state diffs || (# state diffs: intial + repeated) as u32 || sorted state diffs by ]` + let state_diffs_compressed = compress_state_diffs(state_diffs.clone()); + l1_messenger_pubdata.extend(state_diffs_compressed); + + if with_uncompressed_state_diffs { + l1_messenger_pubdata.extend((state_diffs.len() as u32).to_be_bytes()); + for state_diff in state_diffs { + l1_messenger_pubdata.extend(state_diff.encode_padded()); + } + } + + l1_messenger_pubdata + } +} + +#[cfg(test)] +mod tests { + use zksync_system_constants::{ACCOUNT_CODE_STORAGE_ADDRESS, BOOTLOADER_ADDRESS}; + use zksync_utils::u256_to_h256; + + use super::*; + + #[test] + fn test_basic_pubdata_building() { + // Just using some constant addresses for tests + let addr1 = BOOTLOADER_ADDRESS; + let addr2 = ACCOUNT_CODE_STORAGE_ADDRESS; + + let user_logs = vec![L1MessengerL2ToL1Log { + l2_shard_id: 0, + is_service: false, + tx_number_in_block: 0, + sender: addr1, + key: 1.into(), + value: 128.into(), + }]; + + let l2_to_l1_messages = vec![hex::decode("deadbeef").unwrap()]; + + let published_bytecodes = vec![hex::decode("aaaabbbb").unwrap()]; + + // For covering more cases, we have two state diffs: + // One with enumeration index present (and so it is a repeated write) and the one without it. + let state_diffs = vec![ + StateDiffRecord { + address: addr2, + key: 155.into(), + derived_key: u256_to_h256(125.into()).0, + enumeration_index: 12, + initial_value: 11.into(), + final_value: 12.into(), + }, + StateDiffRecord { + address: addr2, + key: 156.into(), + derived_key: u256_to_h256(126.into()).0, + enumeration_index: 0, + initial_value: 0.into(), + final_value: 14.into(), + }, + ]; + + let input = PubdataInput { + user_logs, + l2_to_l1_messages, + published_bytecodes, + state_diffs, + }; + + let pubdata = + ethabi::encode(&[ethabi::Token::Bytes(input.build_pubdata(true))])[32..].to_vec(); + + assert_eq!(hex::encode(pubdata), "00000000000000000000000000000000000000000000000000000000000002c700000001000000000000000000000000000000000000000000008001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000100000004deadbeef0000000100000004aaaabbbb0100002a040001000000000000000000000000000000000000000000000000000000000000007e090e0000000c0901000000020000000000000000000000000000000000008002000000000000000000000000000000000000000000000000000000000000009b000000000000000000000000000000000000000000000000000000000000007d000000000000000c000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008002000000000000000000000000000000000000000000000000000000000000009c000000000000000000000000000000000000000000000000000000000000007e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/internals/snapshot.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/snapshot.rs new file mode 100644 index 000000000000..272673d20c1a --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/snapshot.rs @@ -0,0 +1,11 @@ +use zk_evm_1_4_1::vm_state::VmLocalState; + +use crate::vm_1_4_1::bootloader_state::BootloaderStateSnapshot; + +/// A snapshot of the VM that holds enough information to +/// rollback the VM to some historical state. +#[derive(Debug, Clone)] +pub(crate) struct VmSnapshot { + pub(crate) local_state: VmLocalState, + pub(crate) bootloader_state: BootloaderStateSnapshot, +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs new file mode 100644 index 000000000000..82d4a076699f --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/transaction_data.rs @@ -0,0 +1,344 @@ +use std::convert::TryInto; + +use zksync_types::{ + ethabi::{encode, Address, Token}, + fee::{encoding_len, Fee}, + l1::is_l1_tx_type, + l2::{L2Tx, TransactionType}, + transaction_request::{PaymasterParams, TransactionRequest}, + Bytes, Execute, ExecuteTransactionCommon, L2ChainId, L2TxCommonData, Nonce, Transaction, H256, + U256, +}; +use zksync_utils::{address_to_h256, bytecode::hash_bytecode, bytes_to_be_words, h256_to_u256}; + +use crate::vm_1_4_1::{ + constants::{L1_TX_TYPE, MAX_GAS_PER_PUBDATA_BYTE, PRIORITY_TX_MAX_GAS_LIMIT}, + utils::overhead::derive_overhead, +}; + +/// This structure represents the data that is used by +/// the Bootloader to describe the transaction. +#[derive(Debug, Default, Clone)] +pub(crate) struct TransactionData { + pub(crate) tx_type: u8, + pub(crate) from: Address, + pub(crate) to: Address, + pub(crate) gas_limit: U256, + pub(crate) pubdata_price_limit: U256, + pub(crate) max_fee_per_gas: U256, + pub(crate) max_priority_fee_per_gas: U256, + pub(crate) paymaster: Address, + pub(crate) nonce: U256, + pub(crate) value: U256, + // The reserved fields that are unique for different types of transactions. + // E.g. nonce is currently used in all transaction, but it should not be mandatory + // in the long run. + pub(crate) reserved: [U256; 4], + pub(crate) data: Vec, + pub(crate) signature: Vec, + // The factory deps provided with the transaction. + // Note that *only hashes* of these bytecodes are signed by the user + // and they are used in the ABI encoding of the struct. + // TODO: include this into the tx signature as part of SMA-1010 + pub(crate) factory_deps: Vec>, + pub(crate) paymaster_input: Vec, + pub(crate) reserved_dynamic: Vec, + pub(crate) raw_bytes: Option>, +} + +impl From for TransactionData { + fn from(execute_tx: Transaction) -> Self { + match execute_tx.common_data { + ExecuteTransactionCommon::L2(common_data) => { + let nonce = U256::from_big_endian(&common_data.nonce.to_be_bytes()); + + let should_check_chain_id = if matches!( + common_data.transaction_type, + TransactionType::LegacyTransaction + ) && common_data.extract_chain_id().is_some() + { + U256([1, 0, 0, 0]) + } else { + U256::zero() + }; + + // Ethereum transactions do not sign gas per pubdata limit, and so for them we need to use + // some default value. We use the maximum possible value that is allowed by the bootloader + // (i.e. we can not use u64::MAX, because the bootloader requires gas per pubdata for such + // transactions to be higher than `MAX_GAS_PER_PUBDATA_BYTE`). + let gas_per_pubdata_limit = if common_data.transaction_type.is_ethereum_type() { + MAX_GAS_PER_PUBDATA_BYTE.into() + } else { + common_data.fee.gas_per_pubdata_limit + }; + + TransactionData { + tx_type: (common_data.transaction_type as u32) as u8, + from: common_data.initiator_address, + to: execute_tx.execute.contract_address, + gas_limit: common_data.fee.gas_limit, + pubdata_price_limit: gas_per_pubdata_limit, + max_fee_per_gas: common_data.fee.max_fee_per_gas, + max_priority_fee_per_gas: common_data.fee.max_priority_fee_per_gas, + paymaster: common_data.paymaster_params.paymaster, + nonce, + value: execute_tx.execute.value, + reserved: [ + should_check_chain_id, + U256::zero(), + U256::zero(), + U256::zero(), + ], + data: execute_tx.execute.calldata, + signature: common_data.signature, + factory_deps: execute_tx.execute.factory_deps.unwrap_or_default(), + paymaster_input: common_data.paymaster_params.paymaster_input, + reserved_dynamic: vec![], + raw_bytes: execute_tx.raw_bytes.map(|a| a.0), + } + } + ExecuteTransactionCommon::L1(common_data) => { + let refund_recipient = h256_to_u256(address_to_h256(&common_data.refund_recipient)); + TransactionData { + tx_type: common_data.tx_format() as u8, + from: common_data.sender, + to: execute_tx.execute.contract_address, + gas_limit: common_data.gas_limit, + pubdata_price_limit: common_data.gas_per_pubdata_limit, + // It doesn't matter what we put here, since + // the bootloader does not charge anything + max_fee_per_gas: common_data.max_fee_per_gas, + max_priority_fee_per_gas: U256::zero(), + paymaster: Address::default(), + nonce: U256::from(common_data.serial_id.0), // priority op ID + value: execute_tx.execute.value, + reserved: [ + common_data.to_mint, + refund_recipient, + U256::zero(), + U256::zero(), + ], + data: execute_tx.execute.calldata, + // The signature isn't checked for L1 transactions so we don't care + signature: vec![], + factory_deps: execute_tx.execute.factory_deps.unwrap_or_default(), + paymaster_input: vec![], + reserved_dynamic: vec![], + raw_bytes: None, + } + } + ExecuteTransactionCommon::ProtocolUpgrade(common_data) => { + let refund_recipient = h256_to_u256(address_to_h256(&common_data.refund_recipient)); + TransactionData { + tx_type: common_data.tx_format() as u8, + from: common_data.sender, + to: execute_tx.execute.contract_address, + gas_limit: common_data.gas_limit, + pubdata_price_limit: common_data.gas_per_pubdata_limit, + // It doesn't matter what we put here, since + // the bootloader does not charge anything + max_fee_per_gas: common_data.max_fee_per_gas, + max_priority_fee_per_gas: U256::zero(), + paymaster: Address::default(), + nonce: U256::from(common_data.upgrade_id as u16), + value: execute_tx.execute.value, + reserved: [ + common_data.to_mint, + refund_recipient, + U256::zero(), + U256::zero(), + ], + data: execute_tx.execute.calldata, + // The signature isn't checked for L1 transactions so we don't care + signature: vec![], + factory_deps: execute_tx.execute.factory_deps.unwrap_or_default(), + paymaster_input: vec![], + reserved_dynamic: vec![], + raw_bytes: None, + } + } + } + } +} + +impl TransactionData { + pub(crate) fn abi_encode_with_custom_factory_deps( + self, + factory_deps_hashes: Vec, + ) -> Vec { + encode(&[Token::Tuple(vec![ + Token::Uint(U256::from_big_endian(&self.tx_type.to_be_bytes())), + Token::Address(self.from), + Token::Address(self.to), + Token::Uint(self.gas_limit), + Token::Uint(self.pubdata_price_limit), + Token::Uint(self.max_fee_per_gas), + Token::Uint(self.max_priority_fee_per_gas), + Token::Address(self.paymaster), + Token::Uint(self.nonce), + Token::Uint(self.value), + Token::FixedArray(self.reserved.iter().copied().map(Token::Uint).collect()), + Token::Bytes(self.data), + Token::Bytes(self.signature), + Token::Array(factory_deps_hashes.into_iter().map(Token::Uint).collect()), + Token::Bytes(self.paymaster_input), + Token::Bytes(self.reserved_dynamic), + ])]) + } + + pub(crate) fn abi_encode(self) -> Vec { + let factory_deps_hashes = self + .factory_deps + .iter() + .map(|dep| h256_to_u256(hash_bytecode(dep))) + .collect(); + self.abi_encode_with_custom_factory_deps(factory_deps_hashes) + } + + pub(crate) fn into_tokens(self) -> Vec { + let bytes = self.abi_encode(); + assert!(bytes.len() % 32 == 0); + + bytes_to_be_words(bytes) + } + + pub(crate) fn overhead_gas(&self) -> u32 { + let encoded_len = encoding_len( + self.data.len() as u64, + self.signature.len() as u64, + self.factory_deps.len() as u64, + self.paymaster_input.len() as u64, + self.reserved_dynamic.len() as u64, + ); + + derive_overhead(encoded_len) + } + + pub(crate) fn trusted_ergs_limit(&self) -> U256 { + if self.tx_type == L1_TX_TYPE { + // In case we get a users' transactions with unexpected gas limit, we do not let it have more than + // a certain limit + return U256::from(PRIORITY_TX_MAX_GAS_LIMIT).min(self.gas_limit); + } + + // TODO (EVM-66): correctly calculate the trusted gas limit for a transaction + self.gas_limit + } + + pub(crate) fn tx_hash(&self, chain_id: L2ChainId) -> H256 { + if is_l1_tx_type(self.tx_type) { + return self.canonical_l1_tx_hash().unwrap(); + } + + let l2_tx: L2Tx = self.clone().try_into().unwrap(); + let transaction_request: TransactionRequest = l2_tx.into(); + + // It is assumed that the `TransactionData` always has all the necessary components to recover the hash. + transaction_request + .get_tx_hash(chain_id) + .expect("Could not recover L2 transaction hash") + } + + fn canonical_l1_tx_hash(&self) -> Result { + use zksync_types::web3::signing::keccak256; + + if !is_l1_tx_type(self.tx_type) { + return Err(TxHashCalculationError::CannotCalculateL1HashForL2Tx); + } + + let encoded_bytes = self.clone().abi_encode(); + + Ok(H256(keccak256(&encoded_bytes))) + } +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum TxHashCalculationError { + CannotCalculateL1HashForL2Tx, + CannotCalculateL2HashForL1Tx, +} + +impl TryInto for TransactionData { + type Error = TxHashCalculationError; + + fn try_into(self) -> Result { + if is_l1_tx_type(self.tx_type) { + return Err(TxHashCalculationError::CannotCalculateL2HashForL1Tx); + } + + let common_data = L2TxCommonData { + transaction_type: (self.tx_type as u32).try_into().unwrap(), + nonce: Nonce(self.nonce.as_u32()), + fee: Fee { + max_fee_per_gas: self.max_fee_per_gas, + max_priority_fee_per_gas: self.max_priority_fee_per_gas, + gas_limit: self.gas_limit, + gas_per_pubdata_limit: self.pubdata_price_limit, + }, + signature: self.signature, + input: None, + initiator_address: self.from, + paymaster_params: PaymasterParams { + paymaster: self.paymaster, + paymaster_input: self.paymaster_input, + }, + }; + let factory_deps = (!self.factory_deps.is_empty()).then_some(self.factory_deps); + let execute = Execute { + contract_address: self.to, + value: self.value, + calldata: self.data, + factory_deps, + }; + + Ok(L2Tx { + execute, + common_data, + received_timestamp_ms: 0, + raw_bytes: self.raw_bytes.map(Bytes::from), + }) + } +} + +#[cfg(test)] +mod tests { + use zksync_types::fee::encoding_len; + + use super::*; + + #[test] + fn test_consistency_with_encoding_length() { + let transaction = TransactionData { + tx_type: 113, + from: Address::random(), + to: Address::random(), + gas_limit: U256::from(1u32), + pubdata_price_limit: U256::from(1u32), + max_fee_per_gas: U256::from(1u32), + max_priority_fee_per_gas: U256::from(1u32), + paymaster: Address::random(), + nonce: U256::zero(), + value: U256::zero(), + // The reserved fields that are unique for different types of transactions. + // E.g. nonce is currently used in all transaction, but it should not be mandatory + // in the long run. + reserved: [U256::zero(); 4], + data: vec![0u8; 65], + signature: vec![0u8; 75], + // The factory deps provided with the transaction. + // Note that *only hashes* of these bytecodes are signed by the user + // and they are used in the ABI encoding of the struct. + // TODO: include this into the tx signature as part of SMA-1010 + factory_deps: vec![vec![0u8; 32], vec![1u8; 32]], + paymaster_input: vec![0u8; 85], + reserved_dynamic: vec![0u8; 32], + raw_bytes: None, + }; + + let assumed_encoded_len = encoding_len(65, 75, 2, 85, 32); + + let true_encoding_len = transaction.into_tokens().len(); + + assert_eq!(assumed_encoded_len, true_encoding_len); + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/internals/vm_state.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/vm_state.rs new file mode 100644 index 000000000000..a6f1473a6177 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/internals/vm_state.rs @@ -0,0 +1,181 @@ +use zk_evm_1_4_1::{ + aux_structures::{MemoryPage, Timestamp}, + block_properties::BlockProperties, + vm_state::{CallStackEntry, PrimitiveValue, VmState}, + witness_trace::DummyTracer, + zkevm_opcode_defs::{ + system_params::{BOOTLOADER_MAX_MEMORY, INITIAL_FRAME_FORMAL_EH_LOCATION}, + FatPointer, BOOTLOADER_BASE_PAGE, BOOTLOADER_CALLDATA_PAGE, BOOTLOADER_CODE_PAGE, + STARTING_BASE_PAGE, STARTING_TIMESTAMP, + }, +}; +use zkevm_test_harness_1_3_3::INITIAL_MONOTONIC_CYCLE_COUNTER; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::BOOTLOADER_ADDRESS; +use zksync_types::{block::MiniblockHasher, Address, MiniblockNumber}; +use zksync_utils::h256_to_u256; + +use crate::{ + interface::{L1BatchEnv, L2Block, SystemEnv}, + vm_1_4_1::{ + bootloader_state::BootloaderState, + constants::BOOTLOADER_HEAP_PAGE, + old_vm::{ + event_sink::InMemoryEventSink, + history_recorder::HistoryMode, + memory::SimpleMemory, + oracles::{ + decommitter::DecommitterOracle, precompile::PrecompilesProcessorWithHistory, + }, + }, + oracles::storage::StorageOracle, + types::l1_batch::bootloader_initial_memory, + utils::l2_blocks::{assert_next_block, load_last_l2_block}, + }, +}; + +pub type ZkSyncVmState = VmState< + StorageOracle, + SimpleMemory, + InMemoryEventSink, + PrecompilesProcessorWithHistory, + DecommitterOracle, + DummyTracer, +>; + +fn formal_calldata_abi() -> PrimitiveValue { + let fat_pointer = FatPointer { + offset: 0, + memory_page: BOOTLOADER_CALLDATA_PAGE, + start: 0, + length: 0, + }; + + PrimitiveValue { + value: fat_pointer.to_u256(), + is_pointer: true, + } +} + +/// Initialize the vm state and all necessary oracles +pub(crate) fn new_vm_state( + storage: StoragePtr, + system_env: &SystemEnv, + l1_batch_env: &L1BatchEnv, +) -> (ZkSyncVmState, BootloaderState) { + let last_l2_block = if let Some(last_l2_block) = load_last_l2_block(storage.clone()) { + last_l2_block + } else { + // This is the scenario of either the first L2 block ever or + // the first block after the upgrade for support of L2 blocks. + L2Block { + number: l1_batch_env.first_l2_block.number.saturating_sub(1), + timestamp: 0, + hash: MiniblockHasher::legacy_hash( + MiniblockNumber(l1_batch_env.first_l2_block.number) - 1, + ), + } + }; + + assert_next_block(&last_l2_block, &l1_batch_env.first_l2_block); + let first_l2_block = l1_batch_env.first_l2_block; + let storage_oracle: StorageOracle = StorageOracle::new(storage.clone()); + let mut memory = SimpleMemory::default(); + let event_sink = InMemoryEventSink::default(); + let precompiles_processor = PrecompilesProcessorWithHistory::::default(); + let mut decommittment_processor: DecommitterOracle = + DecommitterOracle::new(storage); + + decommittment_processor.populate( + vec![( + h256_to_u256(system_env.base_system_smart_contracts.default_aa.hash), + system_env + .base_system_smart_contracts + .default_aa + .code + .clone(), + )], + Timestamp(0), + ); + + memory.populate( + vec![( + BOOTLOADER_CODE_PAGE, + system_env + .base_system_smart_contracts + .bootloader + .code + .clone(), + )], + Timestamp(0), + ); + + let bootloader_initial_memory = bootloader_initial_memory(l1_batch_env); + memory.populate_page( + BOOTLOADER_HEAP_PAGE as usize, + bootloader_initial_memory.clone(), + Timestamp(0), + ); + + let mut vm = VmState::empty_state( + storage_oracle, + memory, + event_sink, + precompiles_processor, + decommittment_processor, + DummyTracer, + BlockProperties { + default_aa_code_hash: h256_to_u256( + system_env.base_system_smart_contracts.default_aa.hash, + ), + zkporter_is_available: system_env.zk_porter_available, + }, + ); + + vm.local_state.callstack.current.ergs_remaining = system_env.gas_limit; + + let initial_context = CallStackEntry { + this_address: BOOTLOADER_ADDRESS, + msg_sender: Address::zero(), + code_address: BOOTLOADER_ADDRESS, + base_memory_page: MemoryPage(BOOTLOADER_BASE_PAGE), + code_page: MemoryPage(BOOTLOADER_CODE_PAGE), + sp: 0, + pc: 0, + // Note, that since the results are written at the end of the memory + // it is needed to have the entire heap available from the beginning + heap_bound: BOOTLOADER_MAX_MEMORY, + aux_heap_bound: BOOTLOADER_MAX_MEMORY, + exception_handler_location: INITIAL_FRAME_FORMAL_EH_LOCATION, + ergs_remaining: system_env.gas_limit, + this_shard_id: 0, + caller_shard_id: 0, + code_shard_id: 0, + is_static: false, + is_local_frame: false, + context_u128_value: 0, + }; + + // We consider the contract that is being run as a bootloader + vm.push_bootloader_context(INITIAL_MONOTONIC_CYCLE_COUNTER - 1, initial_context); + vm.local_state.timestamp = STARTING_TIMESTAMP; + vm.local_state.memory_page_counter = STARTING_BASE_PAGE; + vm.local_state.monotonic_cycle_counter = INITIAL_MONOTONIC_CYCLE_COUNTER; + vm.local_state.current_ergs_per_pubdata_byte = 0; + vm.local_state.registers[0] = formal_calldata_abi(); + + // Deleting all the historical records brought by the initial + // initialization of the VM to make them permanent. + vm.decommittment_processor.delete_history(); + vm.event_sink.delete_history(); + vm.storage.delete_history(); + vm.memory.delete_history(); + vm.precompiles_processor.delete_history(); + let bootloader_state = BootloaderState::new( + system_env.execution_mode, + bootloader_initial_memory, + first_l2_block, + ); + + (vm, bootloader_state) +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/l1_batch.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/l1_batch.rs new file mode 100644 index 000000000000..ca2f0688154b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/l1_batch.rs @@ -0,0 +1,44 @@ +use zksync_types::U256; +use zksync_utils::{address_to_u256, h256_to_u256}; + +use crate::{interface::L1BatchEnv, vm_1_4_1::utils::fee::get_batch_base_fee}; + +const OPERATOR_ADDRESS_SLOT: usize = 0; +const PREV_BLOCK_HASH_SLOT: usize = 1; +const NEW_BLOCK_TIMESTAMP_SLOT: usize = 2; +const NEW_BLOCK_NUMBER_SLOT: usize = 3; +const FAIR_PUBDATA_PRICE_SLOT: usize = 4; +const FAIR_L2_GAS_PRICE_SLOT: usize = 5; +const EXPECTED_BASE_FEE_SLOT: usize = 6; +const SHOULD_SET_NEW_BLOCK_SLOT: usize = 7; + +/// Returns the initial memory for the bootloader based on the current batch environment. +pub(crate) fn bootloader_initial_memory(l1_batch: &L1BatchEnv) -> Vec<(usize, U256)> { + let (prev_block_hash, should_set_new_block) = l1_batch + .previous_batch_hash + .map(|prev_block_hash| (h256_to_u256(prev_block_hash), U256::one())) + .unwrap_or_default(); + + vec![ + ( + OPERATOR_ADDRESS_SLOT, + address_to_u256(&l1_batch.fee_account), + ), + (PREV_BLOCK_HASH_SLOT, prev_block_hash), + (NEW_BLOCK_TIMESTAMP_SLOT, U256::from(l1_batch.timestamp)), + (NEW_BLOCK_NUMBER_SLOT, U256::from(l1_batch.number.0)), + ( + FAIR_PUBDATA_PRICE_SLOT, + U256::from(l1_batch.fee_input.fair_pubdata_price()), + ), + ( + FAIR_L2_GAS_PRICE_SLOT, + U256::from(l1_batch.fee_input.fair_l2_gas_price()), + ), + ( + EXPECTED_BASE_FEE_SLOT, + U256::from(get_batch_base_fee(l1_batch)), + ), + (SHOULD_SET_NEW_BLOCK_SLOT, should_set_new_block), + ] +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/types/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/types/mod.rs new file mode 100644 index 000000000000..a12005734abb --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/types/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod internals; +mod l1_batch; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs new file mode 100644 index 000000000000..beb85468241b --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs @@ -0,0 +1,70 @@ +//! Utility functions for vm +use zksync_types::{ + fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, + U256, +}; +use zksync_utils::ceil_div; + +use crate::vm_1_4_1::{constants::MAX_GAS_PER_PUBDATA_BYTE, L1BatchEnv}; + +/// Calculates the base fee and gas per pubdata for the given L1 gas price. +pub(crate) fn derive_base_fee_and_gas_per_pubdata( + fee_input: PubdataIndependentBatchFeeModelInput, +) -> (u64, u64) { + let PubdataIndependentBatchFeeModelInput { + fair_l2_gas_price, + fair_pubdata_price, + .. + } = fee_input; + + // The `baseFee` is set in such a way that it is always possible for a transaction to + // publish enough public data while compensating us for it. + let base_fee = std::cmp::max( + fair_l2_gas_price, + ceil_div(fair_pubdata_price, MAX_GAS_PER_PUBDATA_BYTE), + ); + + let gas_per_pubdata = ceil_div(fair_pubdata_price, base_fee); + + (base_fee, gas_per_pubdata) +} + +pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { + if let Some(base_fee) = l1_batch_env.enforced_base_fee { + return base_fee; + } + let (base_fee, _) = + derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_pubdata_independent()); + base_fee +} + +/// Changes the fee model output so that the expected gas per pubdata is smaller than or the `tx_gas_per_pubdata_limit`. +/// This function expects that the currently expected gas per pubdata is greater than the `tx_gas_per_pubdata_limit`. +pub(crate) fn adjust_pubdata_price_for_tx( + mut batch_fee_input: BatchFeeInput, + tx_gas_per_pubdata_limit: U256, +) -> BatchFeeInput { + match &mut batch_fee_input { + BatchFeeInput::L1Pegged(fee_input) => { + // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` + // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` + let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)) + / U256::from(17); + + fee_input.l1_gas_price = new_l1_gas_price.as_u64(); + } + BatchFeeInput::PubdataIndependent(fee_input) => { + // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` + // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` + let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)); + + fee_input.fair_pubdata_price = new_fair_pubdata_price.as_u64(); + } + } + + batch_fee_input +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/l2_blocks.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/l2_blocks.rs new file mode 100644 index 000000000000..e5832f7f5879 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/l2_blocks.rs @@ -0,0 +1,95 @@ +use zksync_state::{ReadStorage, StoragePtr}; +use zksync_system_constants::{ + SYSTEM_CONTEXT_ADDRESS, SYSTEM_CONTEXT_CURRENT_L2_BLOCK_HASHES_POSITION, + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + SYSTEM_CONTEXT_STORED_L2_BLOCK_HASHES, +}; +use zksync_types::{ + block::unpack_block_info, web3::signing::keccak256, AccountTreeId, MiniblockNumber, StorageKey, + H256, U256, +}; +use zksync_utils::{h256_to_u256, u256_to_h256}; + +use crate::interface::{L2Block, L2BlockEnv}; + +pub(crate) fn get_l2_block_hash_key(block_number: u32) -> StorageKey { + let position = h256_to_u256(SYSTEM_CONTEXT_CURRENT_L2_BLOCK_HASHES_POSITION) + + U256::from(block_number % SYSTEM_CONTEXT_STORED_L2_BLOCK_HASHES); + StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + u256_to_h256(position), + ) +} + +pub(crate) fn assert_next_block(prev_block: &L2Block, next_block: &L2BlockEnv) { + if prev_block.number == 0 { + // Special case for the first block it can have the same timestamp as the previous block. + assert!(prev_block.timestamp <= next_block.timestamp); + } else { + assert_eq!(prev_block.number + 1, next_block.number); + assert!(prev_block.timestamp < next_block.timestamp); + } + assert_eq!(prev_block.hash, next_block.prev_block_hash); +} + +/// Returns the hash of the l2_block. +/// `txs_rolling_hash` of the l2_block is calculated the following way: +/// If the l2_block has 0 transactions, then `txs_rolling_hash` is equal to `H256::zero()`. +/// If the l2_block has i transactions, then `txs_rolling_hash` is equal to `H(H_{i-1}, H(tx_i))`, where +/// `H_{i-1}` is the `txs_rolling_hash` of the first i-1 transactions. +pub(crate) fn l2_block_hash( + l2_block_number: MiniblockNumber, + l2_block_timestamp: u64, + prev_l2_block_hash: H256, + txs_rolling_hash: H256, +) -> H256 { + let mut digest: [u8; 128] = [0u8; 128]; + U256::from(l2_block_number.0).to_big_endian(&mut digest[0..32]); + U256::from(l2_block_timestamp).to_big_endian(&mut digest[32..64]); + digest[64..96].copy_from_slice(prev_l2_block_hash.as_bytes()); + digest[96..128].copy_from_slice(txs_rolling_hash.as_bytes()); + + H256(keccak256(&digest)) +} + +/// Get last saved block from storage +pub fn load_last_l2_block(storage: StoragePtr) -> Option { + // Get block number and timestamp + let current_l2_block_info_key = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_L2_BLOCK_INFO_POSITION, + ); + let mut storage_ptr = storage.borrow_mut(); + let current_l2_block_info = storage_ptr.read_value(¤t_l2_block_info_key); + let (block_number, block_timestamp) = unpack_block_info(h256_to_u256(current_l2_block_info)); + let block_number = block_number as u32; + if block_number == 0 { + // The block does not exist yet + return None; + } + + // Get previous block hash + let position = get_l2_block_hash_key(block_number - 1); + let prev_block_hash = storage_ptr.read_value(&position); + + // Get current tx rolling hash + let position = StorageKey::new( + AccountTreeId::new(SYSTEM_CONTEXT_ADDRESS), + SYSTEM_CONTEXT_CURRENT_TX_ROLLING_HASH_POSITION, + ); + let current_tx_rolling_hash = storage_ptr.read_value(&position); + + // Calculate current hash + let current_block_hash = l2_block_hash( + MiniblockNumber(block_number), + block_timestamp, + prev_block_hash, + current_tx_rolling_hash, + ); + + Some(L2Block { + number: block_number, + timestamp: block_timestamp, + hash: current_block_hash, + }) +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/logs.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/logs.rs new file mode 100644 index 000000000000..079c90a07fad --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/logs.rs @@ -0,0 +1,37 @@ +use zk_evm_1_4_1::aux_structures::{LogQuery, Timestamp}; +use zksync_state::WriteStorage; +use zksync_types::{l2_to_l1_log::L2ToL1Log, StorageLogQueryType, VmEvent}; + +use crate::{ + glue::GlueInto, + interface::L1BatchEnv, + vm_1_4_1::{ + old_vm::{events::merge_events, history_recorder::HistoryMode}, + types::internals::ZkSyncVmState, + }, +}; + +pub(crate) fn collect_events_and_l1_system_logs_after_timestamp( + vm_state: &ZkSyncVmState, + batch_env: &L1BatchEnv, + from_timestamp: Timestamp, +) -> (Vec, Vec) { + let (raw_events, l1_messages) = vm_state + .event_sink + .get_events_and_l2_l1_logs_after_timestamp(from_timestamp); + let events = merge_events(raw_events) + .into_iter() + .map(|e| e.into_vm_event(batch_env.number)) + .collect(); + ( + events, + l1_messages.into_iter().map(GlueInto::glue_into).collect(), + ) +} + +/// Log query, which handle initial and repeated writes to the storage +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct StorageLogQuery { + pub log_query: LogQuery, + pub log_type: StorageLogQueryType, +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/mod.rs new file mode 100644 index 000000000000..0fb803de5d4e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/mod.rs @@ -0,0 +1,6 @@ +/// Utility functions for the VM. +pub mod fee; +pub mod l2_blocks; +pub(crate) mod logs; +pub mod overhead; +pub mod transaction_encoding; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/overhead.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/overhead.rs new file mode 100644 index 000000000000..5d952a484240 --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/overhead.rs @@ -0,0 +1,8 @@ +use crate::vm_1_4_1::constants::{TX_MEMORY_OVERHEAD_GAS, TX_SLOT_OVERHEAD_GAS}; + +/// In the past, the overhead for transaction depended also on the effective gas per pubdata limit for the transaction. +/// Currently, the approach is more similar to EVM, where only the calldata length and the transaction overhead are taken +/// into account by a constant formula. +pub(crate) fn derive_overhead(encoded_len: usize) -> u32 { + TX_SLOT_OVERHEAD_GAS.max(TX_MEMORY_OVERHEAD_GAS * (encoded_len as u32)) +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/transaction_encoding.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/transaction_encoding.rs new file mode 100644 index 000000000000..5a2668bcba1e --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/transaction_encoding.rs @@ -0,0 +1,16 @@ +use zksync_types::Transaction; + +use crate::vm_1_4_1::types::internals::TransactionData; + +/// Extension for transactions, specific for VM. Required for bypassing the orphan rule +pub trait TransactionVmExt { + /// Get the size of the transaction in tokens. + fn bootloader_encoding_size(&self) -> usize; +} + +impl TransactionVmExt for Transaction { + fn bootloader_encoding_size(&self) -> usize { + let transaction_data: TransactionData = self.clone().into(); + transaction_data.into_tokens().len() + } +} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/vm.rs b/core/lib/multivm/src/versions/vm_1_4_1/vm.rs new file mode 100644 index 000000000000..d87b8d96586c --- /dev/null +++ b/core/lib/multivm/src/versions/vm_1_4_1/vm.rs @@ -0,0 +1,211 @@ +use zkevm_test_harness_1_4_1::witness::sort_storage_access::sort_storage_access_queries; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_types::{ + event::extract_l2tol1logs_from_l1_messenger, + l2_to_l1_log::{SystemL2ToL1Log, UserL2ToL1Log}, + Transaction, +}; +use zksync_utils::bytecode::CompressedBytecodeInfo; + +use crate::{ + glue::GlueInto, + interface::{ + BootloaderMemory, BytecodeCompressionError, CurrentExecutionState, FinishedL1Batch, + L1BatchEnv, L2BlockEnv, SystemEnv, VmExecutionMode, VmExecutionResultAndLogs, VmInterface, + VmInterfaceHistoryEnabled, VmMemoryMetrics, + }, + vm_1_4_1::{ + bootloader_state::BootloaderState, + old_vm::{events::merge_events, history_recorder::HistoryEnabled}, + tracers::dispatcher::TracerDispatcher, + types::internals::{new_vm_state, VmSnapshot, ZkSyncVmState}, + }, + HistoryMode, +}; + +/// Main entry point for Virtual Machine integration. +/// The instance should process only one l1 batch +#[derive(Debug)] +pub struct Vm { + pub(crate) bootloader_state: BootloaderState, + // Current state and oracles of virtual machine + pub(crate) state: ZkSyncVmState, + pub(crate) storage: StoragePtr, + pub(crate) system_env: SystemEnv, + pub(crate) batch_env: L1BatchEnv, + // Snapshots for the current run + pub(crate) snapshots: Vec, + _phantom: std::marker::PhantomData, +} + +impl VmInterface for Vm { + type TracerDispatcher = TracerDispatcher; + + fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr) -> Self { + let (state, bootloader_state) = new_vm_state(storage.clone(), &system_env, &batch_env); + Self { + bootloader_state, + state, + storage, + system_env, + batch_env, + snapshots: vec![], + _phantom: Default::default(), + } + } + + /// Push tx into memory for the future execution + fn push_transaction(&mut self, tx: Transaction) { + self.push_transaction_with_compression(tx, true); + } + + /// Execute VM with custom tracers. + fn inspect( + &mut self, + tracer: Self::TracerDispatcher, + execution_mode: VmExecutionMode, + ) -> VmExecutionResultAndLogs { + self.inspect_inner(tracer, execution_mode, None) + } + + /// Get current state of bootloader memory. + fn get_bootloader_memory(&self) -> BootloaderMemory { + self.bootloader_state.bootloader_memory() + } + + /// Get compressed bytecodes of the last executed transaction + fn get_last_tx_compressed_bytecodes(&self) -> Vec { + self.bootloader_state.get_last_tx_compressed_bytecodes() + } + + fn start_new_l2_block(&mut self, l2_block_env: L2BlockEnv) { + self.bootloader_state.start_new_l2_block(l2_block_env); + } + + /// Get current state of virtual machine. + /// This method should be used only after the batch execution. + /// Otherwise it can panic. + fn get_current_execution_state(&self) -> CurrentExecutionState { + let (deduplicated_events_logs, raw_events, l1_messages) = self.state.event_sink.flatten(); + let events: Vec<_> = merge_events(raw_events) + .into_iter() + .map(|e| e.into_vm_event(self.batch_env.number)) + .collect(); + + let user_l2_to_l1_logs = extract_l2tol1logs_from_l1_messenger(&events); + let system_logs = l1_messages + .into_iter() + .map(|log| SystemL2ToL1Log(log.glue_into())) + .collect(); + let total_log_queries = self.state.event_sink.get_log_queries() + + self + .state + .precompiles_processor + .get_timestamp_history() + .len() + + self.state.storage.get_final_log_queries().len(); + + let storage_log_queries = self.state.storage.get_final_log_queries(); + + let deduped_storage_log_queries = + sort_storage_access_queries(storage_log_queries.iter().map(|log| &log.log_query)).1; + + CurrentExecutionState { + events, + storage_log_queries: storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + deduplicated_storage_log_queries: deduped_storage_log_queries + .into_iter() + .map(GlueInto::glue_into) + .collect(), + used_contract_hashes: self.get_used_contracts(), + user_l2_to_l1_logs: user_l2_to_l1_logs + .into_iter() + .map(|log| UserL2ToL1Log(log.into())) + .collect(), + system_logs, + total_log_queries, + cycles_used: self.state.local_state.monotonic_cycle_counter, + deduplicated_events_logs: deduplicated_events_logs + .into_iter() + .map(GlueInto::glue_into) + .collect(), + storage_refunds: self.state.storage.returned_refunds.inner().clone(), + } + } + + /// Execute transaction with optional bytecode compression. + + /// Inspect transaction with optional bytecode compression. + fn inspect_transaction_with_bytecode_compression( + &mut self, + tracer: Self::TracerDispatcher, + tx: Transaction, + with_compression: bool, + ) -> ( + Result<(), BytecodeCompressionError>, + VmExecutionResultAndLogs, + ) { + self.push_transaction_with_compression(tx, with_compression); + let result = self.inspect_inner(tracer, VmExecutionMode::OneTx, None); + if self.has_unpublished_bytecodes() { + ( + Err(BytecodeCompressionError::BytecodeCompressionFailed), + result, + ) + } else { + (Ok(()), result) + } + } + + fn record_vm_memory_metrics(&self) -> VmMemoryMetrics { + self.record_vm_memory_metrics_inner() + } + + fn gas_remaining(&self) -> u32 { + self.state.local_state.callstack.current.ergs_remaining + } + + fn finish_batch(&mut self) -> FinishedL1Batch { + let result = self.execute(VmExecutionMode::Batch); + let execution_state = self.get_current_execution_state(); + let bootloader_memory = self.get_bootloader_memory(); + FinishedL1Batch { + block_tip_execution_result: result, + final_execution_state: execution_state, + final_bootloader_memory: Some(bootloader_memory), + pubdata_input: Some( + self.bootloader_state + .get_pubdata_information() + .clone() + .build_pubdata(false), + ), + } + } +} + +/// Methods of vm, which required some history manipulations +impl VmInterfaceHistoryEnabled for Vm { + /// Create snapshot of current vm state and push it into the memory + fn make_snapshot(&mut self) { + self.make_snapshot_inner() + } + + /// Rollback vm state to the latest snapshot and destroy the snapshot + fn rollback_to_the_latest_snapshot(&mut self) { + let snapshot = self + .snapshots + .pop() + .expect("Snapshot should be created before rolling it back"); + self.rollback_to_snapshot(snapshot); + } + + /// Pop the latest snapshot from the memory and destroy it + fn pop_snapshot_no_rollback(&mut self) { + self.snapshots + .pop() + .expect("Snapshot should be created before rolling it back"); + } +} From 2f02dca3082b9b34d06f7a035f25b3c4114aba20 Mon Sep 17 00:00:00 2001 From: Jordi Date: Thu, 22 Feb 2024 16:25:02 +0100 Subject: [PATCH 036/106] Add unit test --- core/lib/env_config/src/chain.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index 37ffe46a3328..5b9c5a5798b3 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -205,4 +205,12 @@ mod tests { let actual = CircuitBreakerConfig::from_env().unwrap(); assert_eq!(actual, expected_circuit_breaker_config()); } + + #[test] + fn deafult_state_keeper_mode() { + assert_eq!( + StateKeeperConfig::default().l1_batch_commit_data_generator_mode, + L1BatchCommitDataGeneratorMode::Rollup + ); + } } From 7692025ad0a1341b465310c9946d51563f02fa16 Mon Sep 17 00:00:00 2001 From: Jordi Date: Thu, 22 Feb 2024 16:30:43 +0100 Subject: [PATCH 037/106] Refactor name --- core/lib/env_config/src/chain.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/env_config/src/chain.rs b/core/lib/env_config/src/chain.rs index 5b9c5a5798b3..2a599a5a178a 100644 --- a/core/lib/env_config/src/chain.rs +++ b/core/lib/env_config/src/chain.rs @@ -207,7 +207,7 @@ mod tests { } #[test] - fn deafult_state_keeper_mode() { + fn default_state_keeper_mode() { assert_eq!( StateKeeperConfig::default().l1_batch_commit_data_generator_mode, L1BatchCommitDataGeneratorMode::Rollup From 11a34d486258e2535ab5e11e38ba7e5e2885dc88 Mon Sep 17 00:00:00 2001 From: Igor Aleksanov Date: Thu, 22 Feb 2024 20:27:55 +0400 Subject: [PATCH 038/106] feat(api): Implement TxSink abstraction (#1204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Implements a new abstraction: `TxSink` to be used in `TxSender`. Right now we have to use either `TxProxy` or master pool (e.g. only one component), but the code allows invalid configurations. Moreover, mixing two approaches on the `TxSender` level is unreasonably clunky and complex. Having a single abstraction seems to be a better approach. Additionally, it's a prerequisite for implementing an API layer for the framework. ⚠️ There are quite a few possibilities for improvements here, but I suggest not going down the rabbit hole. As long as it's perceived as an incremental improvement, let's not focus on the adjacent code. We can always revisit this place next time it becomes problematic. --- checks-config/era.dic | 4 +- core/bin/external_node/src/main.rs | 31 +++-- .../api_server/tx_sender/master_pool_sink.rs | 37 ++++++ .../src/api_server/tx_sender/mod.rs | 85 ++++--------- .../src/api_server/tx_sender/proxy.rs | 119 ++++++++++++++---- .../src/api_server/tx_sender/tx_sink.rs | 63 ++++++++++ .../zksync_core/src/api_server/web3/mod.rs | 5 - .../src/api_server/web3/namespaces/eth.rs | 48 +++---- .../src/api_server/web3/namespaces/zks.rs | 18 ++- core/lib/zksync_core/src/lib.rs | 11 +- 10 files changed, 278 insertions(+), 143 deletions(-) create mode 100644 core/lib/zksync_core/src/api_server/tx_sender/master_pool_sink.rs create mode 100644 core/lib/zksync_core/src/api_server/tx_sender/tx_sink.rs diff --git a/checks-config/era.dic b/checks-config/era.dic index 36256d8e34a7..d8248e0afa49 100644 --- a/checks-config/era.dic +++ b/checks-config/era.dic @@ -902,4 +902,6 @@ reimplementation composability md5 shivini -balancer \ No newline at end of file +balancer +lookups +stateful diff --git a/core/bin/external_node/src/main.rs b/core/bin/external_node/src/main.rs index b36e62e16126..735df320e7b9 100644 --- a/core/bin/external_node/src/main.rs +++ b/core/bin/external_node/src/main.rs @@ -13,7 +13,7 @@ use zksync_core::{ api_server::{ execution_sandbox::VmConcurrencyLimiter, healthcheck::HealthCheckHandle, - tx_sender::{ApiContracts, TxSenderBuilder}, + tx_sender::{proxy::TxProxy, ApiContracts, TxSenderBuilder}, web3::{ApiBuilder, Namespace}, }, block_reverter::{BlockReverter, BlockReverterFlags, L1ExecutedBatchesRevert}, @@ -275,11 +275,22 @@ async fn init_tasks( let fee_params_fetcher_handle = tokio::spawn(fee_params_fetcher.clone().run(stop_receiver.clone())); - let (tx_sender, vm_barrier, cache_update_handle) = { - let tx_sender_builder = - TxSenderBuilder::new(config.clone().into(), connection_pool.clone()) - .with_main_connection_pool(connection_pool.clone()) - .with_tx_proxy(main_node_client); + let (tx_sender, vm_barrier, cache_update_handle, proxy_cache_updater_handle) = { + let tx_proxy = TxProxy::new(main_node_client); + let proxy_cache_updater_pool = singleton_pool_builder + .build() + .await + .context("failed to build a tree_pool")?; + let proxy_cache_updater_handle = tokio::spawn( + tx_proxy + .run_account_nonce_sweeper(proxy_cache_updater_pool.clone(), stop_receiver.clone()), + ); + + let tx_sender_builder = TxSenderBuilder::new( + config.clone().into(), + connection_pool.clone(), + Arc::new(tx_proxy), + ); if config.optional.transactions_per_sec_limit.is_some() { tracing::warn!("`transactions_per_sec_limit` option is deprecated and ignored"); @@ -308,7 +319,12 @@ async fn init_tasks( storage_caches, ) .await; - (tx_sender, vm_barrier, cache_update_handle) + ( + tx_sender, + vm_barrier, + cache_update_handle, + proxy_cache_updater_handle, + ) }; let http_server_handles = @@ -359,6 +375,7 @@ async fn init_tasks( task_handles.extend(http_server_handles.tasks); task_handles.extend(ws_server_handles.tasks); task_handles.extend(cache_update_handle); + task_handles.push(proxy_cache_updater_handle); task_handles.extend([ sk_handle, fee_address_migration_handle, diff --git a/core/lib/zksync_core/src/api_server/tx_sender/master_pool_sink.rs b/core/lib/zksync_core/src/api_server/tx_sender/master_pool_sink.rs new file mode 100644 index 000000000000..f6fc7e729371 --- /dev/null +++ b/core/lib/zksync_core/src/api_server/tx_sender/master_pool_sink.rs @@ -0,0 +1,37 @@ +use zksync_dal::{transactions_dal::L2TxSubmissionResult, ConnectionPool}; +use zksync_types::{fee::TransactionExecutionMetrics, l2::L2Tx}; + +use super::{tx_sink::TxSink, SubmitTxError}; +use crate::metrics::{TxStage, APP_METRICS}; + +/// Wrapper for the master DB pool that allows to submit transactions to the mempool. +#[derive(Debug)] +pub struct MasterPoolSink { + master_pool: ConnectionPool, +} + +impl MasterPoolSink { + pub fn new(master_pool: ConnectionPool) -> Self { + Self { master_pool } + } +} + +#[async_trait::async_trait] +impl TxSink for MasterPoolSink { + async fn submit_tx( + &self, + tx: L2Tx, + execution_metrics: TransactionExecutionMetrics, + ) -> Result { + let submission_res_handle = self + .master_pool + .access_storage_tagged("api") + .await? + .transactions_dal() + .insert_transaction_l2(tx, execution_metrics) + .await; + + APP_METRICS.processed_txs[&TxStage::Mempool(submission_res_handle)].inc(); + Ok(submission_res_handle) + } +} diff --git a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs index 8fe0380e7510..ba1463038277 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs @@ -25,9 +25,9 @@ use zksync_types::{ MAX_NEW_FACTORY_DEPS, U256, }; use zksync_utils::h256_to_u256; -use zksync_web3_decl::jsonrpsee::http_client::HttpClient; -pub(super) use self::{proxy::TxProxy, result::SubmitTxError}; +pub(super) use self::result::SubmitTxError; +use self::tx_sink::TxSink; use crate::{ api_server::{ execution_sandbox::{ @@ -38,15 +38,16 @@ use crate::{ tx_sender::result::ApiCallResult, }, fee_model::BatchFeeModelInputProvider, - metrics::{TxStage, APP_METRICS}, state_keeper::seal_criteria::{ConditionalSealer, NoopSealer, SealData}, utils::pending_protocol_version, }; -mod proxy; +pub mod master_pool_sink; +pub mod proxy; mod result; #[cfg(test)] pub(crate) mod tests; +pub mod tx_sink; #[derive(Debug, Clone)] pub struct MultiVMBaseSystemContracts { @@ -141,21 +142,22 @@ pub struct TxSenderBuilder { config: TxSenderConfig, /// Connection pool for read requests. replica_connection_pool: ConnectionPool, - /// Connection pool for write requests. If not set, `proxy` must be set. - master_connection_pool: Option, - /// Proxy to submit transactions to the network. If not set, `master_connection_pool` must be set. - proxy: Option, + /// Sink to be used to persist transactions. + tx_sink: Arc, /// Batch sealer used to check whether transaction can be executed by the sequencer. sealer: Option>, } impl TxSenderBuilder { - pub fn new(config: TxSenderConfig, replica_connection_pool: ConnectionPool) -> Self { + pub fn new( + config: TxSenderConfig, + replica_connection_pool: ConnectionPool, + tx_sink: Arc, + ) -> Self { Self { config, replica_connection_pool, - master_connection_pool: None, - proxy: None, + tx_sink, sealer: None, } } @@ -165,16 +167,6 @@ impl TxSenderBuilder { self } - pub fn with_tx_proxy(mut self, client: HttpClient) -> Self { - self.proxy = Some(TxProxy::new(client)); - self - } - - pub fn with_main_connection_pool(mut self, master_connection_pool: ConnectionPool) -> Self { - self.master_connection_pool = Some(master_connection_pool); - self - } - pub async fn build( self, batch_fee_input_provider: Arc, @@ -182,21 +174,15 @@ impl TxSenderBuilder { api_contracts: ApiContracts, storage_caches: PostgresStorageCaches, ) -> TxSender { - assert!( - self.master_connection_pool.is_some() || self.proxy.is_some(), - "Either master connection pool or proxy must be set" - ); - // Use noop sealer if no sealer was explicitly provided. let sealer = self.sealer.unwrap_or_else(|| Arc::new(NoopSealer)); TxSender(Arc::new(TxSenderInner { sender_config: self.config, - master_connection_pool: self.master_connection_pool, + tx_sink: self.tx_sink, replica_connection_pool: self.replica_connection_pool, batch_fee_input_provider, api_contracts, - proxy: self.proxy, vm_concurrency_limiter, storage_caches, sealer, @@ -244,13 +230,12 @@ impl TxSenderConfig { pub struct TxSenderInner { pub(super) sender_config: TxSenderConfig, - pub master_connection_pool: Option, + /// Sink to be used to persist transactions. + pub tx_sink: Arc, pub replica_connection_pool: ConnectionPool, // Used to keep track of gas prices for the fee ticker. pub batch_fee_input_provider: Arc, pub(super) api_contracts: ApiContracts, - /// Optional transaction proxy to be used for transaction submission. - pub(super) proxy: Option, /// Used to limit the amount of VMs that can be executed simultaneously. pub(super) vm_concurrency_limiter: Arc, // Caches used in VM execution. @@ -348,41 +333,14 @@ impl TxSender { let stage_started_at = Instant::now(); self.ensure_tx_executable(tx.clone().into(), &execution_output.metrics, true)?; - if let Some(proxy) = &self.0.proxy { - // We're running an external node: we have to proxy the transaction to the main node. - // But before we do that, save the tx to cache in case someone will request it - // Before it reaches the main node. - proxy.save_tx(tx.clone()).await; - proxy.submit_tx(&tx).await?; - // Now, after we are sure that the tx is on the main node, remove it from cache - // since we don't want to store txs that might have been replaced or otherwise removed - // from the mempool. - proxy.forget_tx(tx.hash()).await; - SANDBOX_METRICS.submit_tx[&SubmitTxStage::TxProxy].observe(stage_started_at.elapsed()); - APP_METRICS.processed_txs[&TxStage::Proxied].inc(); - return Ok(L2TxSubmissionResult::Proxied); - } else { - assert!( - self.0.master_connection_pool.is_some(), - "TxSender is instantiated without both master connection pool and tx proxy" - ); - } - let nonce = tx.common_data.nonce.0; let hash = tx.hash(); let initiator_account = tx.initiator_account(); let submission_res_handle = self .0 - .master_connection_pool - .as_ref() - .unwrap() // Checked above - .access_storage_tagged("api") - .await? - .transactions_dal() - .insert_transaction_l2(tx, execution_output.metrics) - .await; - - APP_METRICS.processed_txs[&TxStage::Mempool(submission_res_handle)].inc(); + .tx_sink + .submit_tx(tx, execution_output.metrics) + .await?; match submission_res_handle { L2TxSubmissionResult::AlreadyExecuted => { @@ -399,6 +357,11 @@ impl TxSender { )) } L2TxSubmissionResult::Duplicate => Err(SubmitTxError::IncorrectTx(TxDuplication(hash))), + L2TxSubmissionResult::Proxied => { + SANDBOX_METRICS.submit_tx[&SubmitTxStage::TxProxy] + .observe(stage_started_at.elapsed()); + Ok(submission_res_handle) + } _ => { SANDBOX_METRICS.submit_tx[&SubmitTxStage::DbInsert] .observe(stage_started_at.elapsed()); diff --git a/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs b/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs index 5cd228745980..4a702fbbeede 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/proxy.rs @@ -6,18 +6,25 @@ use std::{ }; use tokio::sync::{watch, RwLock}; -use zksync_dal::ConnectionPool; +use zksync_dal::{transactions_dal::L2TxSubmissionResult, ConnectionPool}; use zksync_types::{ api::{BlockId, Transaction, TransactionDetails, TransactionId}, + fee::TransactionExecutionMetrics, l2::L2Tx, Address, Nonce, H256, }; use zksync_web3_decl::{ - error::{ClientRpcContext, EnrichedClientResult}, + error::{ClientRpcContext, EnrichedClientResult, Web3Error}, jsonrpsee::http_client::HttpClient, namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; +use super::{tx_sink::TxSink, SubmitTxError}; +use crate::{ + api_server::web3::backend_jsonrpsee::internal_error, + metrics::{TxStage, APP_METRICS}, +}; + #[derive(Debug, Clone, Default)] pub(crate) struct TxCache { inner: Arc>, @@ -116,29 +123,37 @@ impl TxProxy { } } - pub async fn find_tx(&self, tx_hash: H256) -> Option { - self.tx_cache.get_tx(tx_hash).await + async fn submit_tx_impl(&self, tx: &L2Tx) -> EnrichedClientResult { + let input_data = tx.common_data.input_data().expect("raw tx is absent"); + let raw_tx = zksync_types::Bytes(input_data.to_vec()); + let tx_hash = tx.hash(); + tracing::info!("Proxying tx {tx_hash:?}"); + self.client + .send_raw_transaction(raw_tx) + .rpc_context("send_raw_transaction") + .with_arg("tx_hash", &tx_hash) + .await } - pub async fn forget_tx(&self, tx_hash: H256) { - self.tx_cache.remove_tx(tx_hash).await; + async fn save_tx(&self, tx: L2Tx) { + self.tx_cache.push(tx).await; } - pub async fn save_tx(&self, tx: L2Tx) { - self.tx_cache.push(tx).await; + async fn find_tx(&self, tx_hash: H256) -> Option { + self.tx_cache.get_tx(tx_hash).await } - pub async fn get_nonces_by_account(&self, account_address: Address) -> BTreeSet { - self.tx_cache.get_nonces_for_account(account_address).await + async fn forget_tx(&self, tx_hash: H256) { + self.tx_cache.remove_tx(tx_hash).await; } - pub async fn next_nonce_by_initiator_account( + async fn next_nonce_by_initiator_account( &self, account_address: Address, current_nonce: u32, ) -> Nonce { let mut pending_nonce = Nonce(current_nonce); - let nonces = self.get_nonces_by_account(account_address).await; + let nonces = self.tx_cache.get_nonces_for_account(account_address).await; for nonce in nonces.range(pending_nonce + 1..) { // If nonce is not sequential, then we should not increment nonce. if nonce == &pending_nonce { @@ -151,19 +166,7 @@ impl TxProxy { pending_nonce } - pub async fn submit_tx(&self, tx: &L2Tx) -> EnrichedClientResult { - let input_data = tx.common_data.input_data().expect("raw tx is absent"); - let raw_tx = zksync_types::Bytes(input_data.to_vec()); - let tx_hash = tx.hash(); - tracing::info!("Proxying tx {tx_hash:?}"); - self.client - .send_raw_transaction(raw_tx) - .rpc_context("send_raw_transaction") - .with_arg("tx_hash", &tx_hash) - .await - } - - pub async fn request_tx(&self, id: TransactionId) -> EnrichedClientResult> { + async fn request_tx(&self, id: TransactionId) -> EnrichedClientResult> { match id { TransactionId::Block(BlockId::Hash(block), index) => { self.client @@ -191,7 +194,7 @@ impl TxProxy { } } - pub async fn request_tx_details( + async fn request_tx_details( &self, hash: H256, ) -> EnrichedClientResult> { @@ -211,3 +214,67 @@ impl TxProxy { tx_cache.run_updates(pool, stop_receiver) } } + +#[async_trait::async_trait] +impl TxSink for TxProxy { + async fn submit_tx( + &self, + tx: L2Tx, + _execution_metrics: TransactionExecutionMetrics, + ) -> Result { + // We're running an external node: we have to proxy the transaction to the main node. + // But before we do that, save the tx to cache in case someone will request it + // Before it reaches the main node. + self.save_tx(tx.clone()).await; + self.submit_tx_impl(&tx).await?; + // Now, after we are sure that the tx is on the main node, remove it from cache + // since we don't want to store txs that might have been replaced or otherwise removed + // from the mempool. + self.forget_tx(tx.hash()).await; + APP_METRICS.processed_txs[&TxStage::Proxied].inc(); + Ok(L2TxSubmissionResult::Proxied) + } + + async fn lookup_pending_nonce( + &self, + _method_name: &'static str, + account_address: Address, + last_known_nonce: u32, + ) -> Result, Web3Error> { + // EN: get pending nonces from the transaction cache + // We don't have mempool in EN, it's safe to use the proxy cache as a mempool + Ok(Some( + self.next_nonce_by_initiator_account(account_address, last_known_nonce) + .await + .0 + .into(), + )) + } + + async fn lookup_tx( + &self, + method_name: &'static str, + id: TransactionId, + ) -> Result, Web3Error> { + if let TransactionId::Hash(hash) = id { + // If the transaction is not in the db, check the cache + if let Some(tx) = self.find_tx(hash).await { + return Ok(Some(tx.into())); + } + } + // If the transaction is not in the cache, query main node + self.request_tx(id) + .await + .map_err(|err| internal_error(method_name, err)) + } + + async fn lookup_tx_details( + &self, + method_name: &'static str, + hash: H256, + ) -> Result, Web3Error> { + self.request_tx_details(hash) + .await + .map_err(|err| internal_error(method_name, err)) + } +} diff --git a/core/lib/zksync_core/src/api_server/tx_sender/tx_sink.rs b/core/lib/zksync_core/src/api_server/tx_sender/tx_sink.rs new file mode 100644 index 000000000000..0cf353470abf --- /dev/null +++ b/core/lib/zksync_core/src/api_server/tx_sender/tx_sink.rs @@ -0,0 +1,63 @@ +use zksync_dal::transactions_dal::L2TxSubmissionResult; +use zksync_types::{ + api::{Transaction, TransactionDetails, TransactionId}, + fee::TransactionExecutionMetrics, + l2::L2Tx, + Address, Nonce, H256, +}; +use zksync_web3_decl::error::Web3Error; + +use super::SubmitTxError; + +/// An abstraction of "destination" for transactions that should be propagated to the mempool. +/// +/// By default, `TxSender` always has access to the Postgres replica pool, but this only provides read-only progress. +/// However, `TxSender` should be able to propagate transactions as well, and for that purpose the implementation may +/// be different. For example, main node has access to the master pool, and external node has a proxy that submits +/// transaction to the main node. +/// +/// Both approaches represent different implementations of `TxSink` trait. +/// +/// Additionally, `TxSink` may be stateful: e.g. if the effects of transaction submission are not immediately visible +/// through the replica pool, `TxSink` may implement methods to allow cache-like lookups. These methods are not mandatory +/// and may be implemented as no-ops. +#[async_trait::async_trait] +pub trait TxSink: std::fmt::Debug + Send + Sync + 'static { + /// Ensures that transaction is propagated to the mempool. + async fn submit_tx( + &self, + tx: L2Tx, + execution_metrics: TransactionExecutionMetrics, + ) -> Result; + + /// Attempts to look up the pending nonce for the account in the sink-specific storage. + /// By default, returns `Ok(None)`. + async fn lookup_pending_nonce( + &self, + _method_name: &'static str, + _account_address: Address, + _last_known_nonce: u32, + ) -> Result, Web3Error> { + Ok(None) + } + + /// Attempts to look up the transaction by its API ID in the sink-specific storage. + /// By default, returns `Ok(None)`. + async fn lookup_tx( + &self, + _method_name: &'static str, + _id: TransactionId, + ) -> Result, Web3Error> { + Ok(None) + } + + /// Attempts to look up the transaction details by its hash in the sink-specific storage. + /// By default, returns `Ok(None)`. + async fn lookup_tx_details( + &self, + _method_name: &'static str, + _hash: H256, + ) -> Result, Web3Error> { + Ok(None) + } +} diff --git a/core/lib/zksync_core/src/api_server/web3/mod.rs b/core/lib/zksync_core/src/api_server/web3/mod.rs index 2e007d946734..cf055b946c00 100644 --- a/core/lib/zksync_core/src/api_server/web3/mod.rs +++ b/core/lib/zksync_core/src/api_server/web3/mod.rs @@ -427,11 +427,6 @@ impl FullApiParams { ); let mut tasks = vec![tokio::spawn(update_task)]; - if let Some(tx_proxy) = &self.tx_sender.0.proxy { - let task = tx_proxy - .run_account_nonce_sweeper(self.updaters_pool.clone(), stop_receiver.clone()); - tasks.push(tokio::spawn(task)); - } let pub_sub = if matches!(transport, ApiTransport::WebSocket(_)) && self.namespaces.contains(&Namespace::Pubsub) { diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs index 76780075f036..0f3590a54fcc 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/eth.rs @@ -485,16 +485,17 @@ impl EthNamespace { if matches!(block_id, BlockId::Number(BlockNumber::Pending)) { let account_nonce_u64 = u64::try_from(account_nonce) .map_err(|err| internal_error(method_name, anyhow::anyhow!(err)))?; - account_nonce = if let Some(proxy) = &self.state.tx_sender.0.proxy { - // EN: get pending nonces from the transaction cache - // We don't have mempool in EN, it's safe to use the proxy cache as a mempool - proxy - .next_nonce_by_initiator_account(address, account_nonce_u64 as u32) - .await - .0 - .into() + account_nonce = if let Some(account_nonce) = self + .state + .tx_sender + .0 + .tx_sink + .lookup_pending_nonce(method_name, address, account_nonce_u64 as u32) + .await? + { + account_nonce.0.into() } else { - // Main node: get pending nonces from the mempool + // No nonce hint in the sink: get pending nonces from the mempool connection .transactions_web3_dal() .next_nonce_by_initiator_account(address, account_nonce_u64) @@ -527,27 +528,14 @@ impl EthNamespace { .await .map_err(|err| internal_error(METHOD_NAME, err)); - if let Some(proxy) = &self.state.tx_sender.0.proxy { - // We're running an external node - check the proxy cache in - // case the transaction was proxied but not yet synced back to us - if let Ok(Some(tx)) = &transaction { - // If the transaction is already in the db, remove it from cache - proxy.forget_tx(tx.hash).await - } else { - if let TransactionId::Hash(hash) = id { - // If the transaction is not in the db, check the cache - if let Some(tx) = proxy.find_tx(hash).await { - transaction = Ok(Some(tx.into())); - } - } - if !matches!(transaction, Ok(Some(_))) { - // If the transaction is not in the db or cache, query main node - transaction = proxy - .request_tx(id) - .await - .map_err(|err| internal_error(METHOD_NAME, err)); - } - } + if let Ok(None) = transaction { + transaction = self + .state + .tx_sender + .0 + .tx_sink + .lookup_tx(METHOD_NAME, id) + .await; } method_latency.observe(); diff --git a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs index 6543e37e3937..6bef4b5e2346 100644 --- a/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs +++ b/core/lib/zksync_core/src/api_server/web3/namespaces/zks.rs @@ -480,16 +480,14 @@ impl ZksNamespace { .map_err(|err| internal_error(METHOD_NAME, err)); drop(storage); - if let Some(proxy) = &self.state.tx_sender.0.proxy { - // We're running an external node - we should query the main node directly - // in case the transaction was proxied but not yet synced back to us - if matches!(tx_details, Ok(None)) { - // If the transaction is not in the db, query main node for details - tx_details = proxy - .request_tx_details(hash) - .await - .map_err(|err| internal_error(METHOD_NAME, err)); - } + if let Ok(None) = tx_details { + tx_details = self + .state + .tx_sender + .0 + .tx_sink + .lookup_tx_details(METHOD_NAME, hash) + .await; } method_latency.observe(); diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index f7b1f9fb4a7d..92416d6a6863 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -3,6 +3,7 @@ use std::{net::Ipv4Addr, str::FromStr, sync::Arc, time::Instant}; use anyhow::Context as _; +use api_server::tx_sender::master_pool_sink::MasterPoolSink; use fee_model::{ApiFeeInputProvider, BatchFeeModelInputProvider, MainNodeFeeInputProvider}; use futures::channel::oneshot; use prometheus_exporter::PrometheusExporterConfig; @@ -1101,9 +1102,13 @@ async fn build_tx_sender( storage_caches: PostgresStorageCaches, ) -> (TxSender, VmConcurrencyBarrier) { let sequencer_sealer = SequencerSealer::new(state_keeper_config.clone()); - let tx_sender_builder = TxSenderBuilder::new(tx_sender_config.clone(), replica_pool.clone()) - .with_main_connection_pool(master_pool) - .with_sealer(Arc::new(sequencer_sealer)); + let master_pool_sink = MasterPoolSink::new(master_pool); + let tx_sender_builder = TxSenderBuilder::new( + tx_sender_config.clone(), + replica_pool.clone(), + Arc::new(master_pool_sink), + ) + .with_sealer(Arc::new(sequencer_sealer)); let max_concurrency = web3_json_config.vm_concurrency_limit(); let (vm_concurrency_limiter, vm_barrier) = VmConcurrencyLimiter::new(max_concurrency); From 3b9db65dd2f893b106040450a5665953ab071c9f Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 22 Feb 2024 13:29:16 -0300 Subject: [PATCH 039/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 9ab2f16841b0..d36ce9a928de 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 9ab2f16841b04e1f35d1646352b99a61a2a741c4 +Subproject commit d36ce9a928de49567837f1dbd43a59f20c287963 From 0b27ef1079a1819c72c47d0cae9351de3d2c25d1 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 22 Feb 2024 13:44:11 -0300 Subject: [PATCH 040/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index d36ce9a928de..9e1059ab9bc2 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit d36ce9a928de49567837f1dbd43a59f20c287963 +Subproject commit 9e1059ab9bc20d7e97a26757ac426513a1649e1e From dee8aea1dd1802cbe84fe2bd13117d089bbb9bf0 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 22 Feb 2024 14:22:07 -0300 Subject: [PATCH 041/106] Update contracts submodule commit --- .gitmodules | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 9f35d9639867..71fef99dc0ba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "contracts"] path = contracts url = https://github.com/LambdaClass/era-contracts.git -branch = feat_get_rid_of_solpp_need +branch = feat_validium_mode diff --git a/contracts b/contracts index 9e1059ab9bc2..31707c9abc9d 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 9e1059ab9bc20d7e97a26757ac426513a1649e1e +Subproject commit 31707c9abc9d6df8be7e9e031245081ef460c194 From cabd73a04e7f5a910e5b7df8c47f012a7608cd29 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Thu, 22 Feb 2024 18:28:39 +0100 Subject: [PATCH 042/106] set BatchCommitDataGenerator in external node init --- core/bin/external_node/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core/bin/external_node/src/main.rs b/core/bin/external_node/src/main.rs index a5b5a2473e20..a2a96dfc6883 100644 --- a/core/bin/external_node/src/main.rs +++ b/core/bin/external_node/src/main.rs @@ -240,8 +240,14 @@ async fn init_tasks( .context("failed initializing metadata calculator")?; healthchecks.push(Box::new(metadata_calculator.tree_health_check())); - let l1_batch_commit_data_generator = Arc::new(RollupModeL1BatchCommitDataGenerator {}); - + let l1_batch_commit_data_generator: Arc = match config + .l1_batch_commit_data_generator_mode + { + L1BatchCommitDataGeneratorMode::Rollup => Arc::new(RollupModeL1BatchCommitDataGenerator {}), + L1BatchCommitDataGeneratorMode::Validium => { + Arc::new(ValidiumModeL1BatchCommitDataGenerator {}) + } + }; let consistency_checker = ConsistencyChecker::new( &config .required From ea4daa741d1c340f3771a48990318b7e0906fd47 Mon Sep 17 00:00:00 2001 From: Santiago Pittella Date: Thu, 22 Feb 2024 19:10:04 +0100 Subject: [PATCH 043/106] add panic if commitment mode differs --- contracts | 2 +- core/lib/config/src/configs/chain.rs | 21 ++++++++++++++++- core/lib/eth_client/src/clients/http/query.rs | 8 +++++-- .../eth_client/src/clients/http/signing.rs | 13 +++++++++-- core/lib/zksync_core/src/lib.rs | 23 ++++++++++++++++++- 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/contracts b/contracts index ceb214b7650c..304f902f6c6d 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit ceb214b7650c6102703a9b5569a4056fe97a3be4 +Subproject commit 304f902f6c6d1a2aa2c545069f41747dd71c9012 diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index 7a0504503c19..bbce533acb31 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -1,7 +1,7 @@ use std::{str::FromStr, time::Duration}; use serde::Deserialize; -use zksync_basic_types::{network::Network, Address, L2ChainId}; +use zksync_basic_types::{network::Network, Address, Bytes, L2ChainId}; #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct NetworkConfig { @@ -52,6 +52,25 @@ pub enum L1BatchCommitDataGeneratorMode { Validium, } +// The cases are extracted from the `PubdataPricingMode` enum in the L1 contracts, +// And knowing that, in Ethereum, the response is the index of the enum case. +// If the bytes are "0x0000000000000000000000000000000000000000000000000000000000000000" i want the rollup case, +// If the bytes are "0x0000000000000000000000000000000000000000000000000000000000000001" i want the validium case, +// Else, an error. +impl L1BatchCommitDataGeneratorMode { + pub fn from_eth_response(response: &Bytes) -> Result { + match &response.0.as_slice() { + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] => { + Ok(Self::Rollup) + } + &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] => { + Ok(Self::Validium) + } + _ => Err("Invalid response".to_string()), + } + } +} + #[derive(Debug, Deserialize, Clone, PartialEq, Default)] pub struct StateKeeperConfig { /// The max number of slots for txs in a block before it should be sealed by the slots sealer. diff --git a/core/lib/eth_client/src/clients/http/query.rs b/core/lib/eth_client/src/clients/http/query.rs index d1abb74c46d6..f41d9c0bdeef 100644 --- a/core/lib/eth_client/src/clients/http/query.rs +++ b/core/lib/eth_client/src/clients/http/query.rs @@ -7,8 +7,8 @@ use zksync_types::web3::{ ethabi, transports::Http, types::{ - Address, Block, BlockId, BlockNumber, Bytes, Filter, Log, Transaction, TransactionId, - TransactionReceipt, H256, U256, U64, + Address, Block, BlockId, BlockNumber, Bytes, CallRequest, Filter, Log, Transaction, + TransactionId, TransactionReceipt, H256, U256, U64, }, Web3, }; @@ -40,6 +40,10 @@ impl QueryClient { let transport = Http::new(node_url)?; Ok(transport.into()) } + + pub async fn call(&self, params: CallRequest) -> Result { + self.web3.eth().call(params, None).await + } } #[async_trait] diff --git a/core/lib/eth_client/src/clients/http/signing.rs b/core/lib/eth_client/src/clients/http/signing.rs index 6e3dd3d223d8..668176378aa4 100644 --- a/core/lib/eth_client/src/clients/http/signing.rs +++ b/core/lib/eth_client/src/clients/http/signing.rs @@ -11,8 +11,8 @@ use zksync_types::{ ethabi, transports::Http, types::{ - Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt, - H160, H256, U256, U64, + Address, Block, BlockId, BlockNumber, CallRequest, Filter, Log, Transaction, + TransactionReceipt, H160, H256, U256, U64, }, }, L1ChainId, PackedEthSignature, EIP_1559_TX_TYPE, @@ -97,6 +97,15 @@ impl fmt::Debug for SigningClient { } } +impl SigningClient +where + S: EthereumSigner, +{ + pub async fn call(&self, params: CallRequest) -> Result { + self.query_client.call(params).await + } +} + #[async_trait] impl EthInterface for SigningClient { async fn nonce_at_for_account( diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 99c0f665ef79..22c17aaba758 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -44,8 +44,9 @@ use zksync_types::{ protocol_version::{L1VerifierConfig, VerifierParams}, system_contracts::get_system_smart_contracts, web3::contract::tokens::Detokenize, - L2ChainId, PackedEthSignature, ProtocolVersionId, + Bytes, L2ChainId, PackedEthSignature, ProtocolVersionId, }; +use zksync_web3_decl::types::CallRequest; use crate::{ api_server::{ @@ -630,6 +631,26 @@ pub async fn initialize_components( Arc::new(ValidiumModeL1BatchCommitDataGenerator {}) } }; + + let current_commitment_mode_eth_response = eth_client + .call( + CallRequest::builder() + .to((&contracts_config).executor_facet_addr.clone()) + .data(serde_json::from_str::(r#""0x252e5966""#).unwrap()) // The selector of "getPubdataPriceMode()" + .build(), + ) + .await + .unwrap(); + + let current_commitment_mode = L1BatchCommitDataGeneratorMode::from_eth_response( + ¤t_commitment_mode_eth_response, + ) + .unwrap(); + + if current_commitment_mode != state_keeper_config.l1_batch_commit_data_generator_mode { + panic!("The selected L1BatchCommitDataGeneratorMode does not match the existing commitment mode"); + } + let eth_tx_aggregator_actor = EthTxAggregator::new( eth_sender.sender.clone(), Aggregator::new( From fcee5d13eb05111049eb574a13c040f5b0fa4117 Mon Sep 17 00:00:00 2001 From: Santiago Pittella Date: Thu, 22 Feb 2024 19:57:16 +0100 Subject: [PATCH 044/106] use assert_eq, panic if eth response is invalid --- core/lib/config/src/configs/chain.rs | 8 ++++---- core/lib/zksync_core/src/lib.rs | 15 +++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index bbce533acb31..69c7e38793c5 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -58,15 +58,15 @@ pub enum L1BatchCommitDataGeneratorMode { // If the bytes are "0x0000000000000000000000000000000000000000000000000000000000000001" i want the validium case, // Else, an error. impl L1BatchCommitDataGeneratorMode { - pub fn from_eth_response(response: &Bytes) -> Result { + pub fn from_eth_response(response: &Bytes) -> Self { match &response.0.as_slice() { &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] => { - Ok(Self::Rollup) + Self::Rollup } &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] => { - Ok(Self::Validium) + Self::Validium } - _ => Err("Invalid response".to_string()), + _response => panic!("Invalid response: {:?}", _response), } } } diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 22c17aaba758..1baae27c3b33 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -640,16 +640,19 @@ pub async fn initialize_components( .build(), ) .await - .unwrap(); + .context("failed to get the current commitment mode from the Ethereum")?; let current_commitment_mode = L1BatchCommitDataGeneratorMode::from_eth_response( ¤t_commitment_mode_eth_response, - ) - .unwrap(); + ); - if current_commitment_mode != state_keeper_config.l1_batch_commit_data_generator_mode { - panic!("The selected L1BatchCommitDataGeneratorMode does not match the existing commitment mode"); - } + assert_eq!( + current_commitment_mode, + state_keeper_config.l1_batch_commit_data_generator_mode, + "The selected L1BatchCommitDataGeneratorMode ({:?}) does not match the existing commitment mode ({:?})", + state_keeper_config.l1_batch_commit_data_generator_mode, + current_commitment_mode + ); let eth_tx_aggregator_actor = EthTxAggregator::new( eth_sender.sender.clone(), From 96035d838546dca47e26a9975cd10bd7a23a7491 Mon Sep 17 00:00:00 2001 From: Santiago Pittella Date: Thu, 22 Feb 2024 20:11:36 +0100 Subject: [PATCH 045/106] use a function for the function selector --- core/lib/zksync_core/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 1baae27c3b33..4a1d57b45cda 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -103,6 +103,11 @@ pub mod sync_layer; pub mod temp_config_store; mod utils; +/// Returns the selector of the `getPubdataPriceMode()`. +fn get_pubdata_price_mode_selector() -> Bytes { + serde_json::from_str::(r#""0x252e5966""#).unwrap() +} + /// Inserts the initial information about zkSync tokens into the database. pub async fn genesis_init( postgres_config: &PostgresConfig, @@ -636,7 +641,7 @@ pub async fn initialize_components( .call( CallRequest::builder() .to((&contracts_config).executor_facet_addr.clone()) - .data(serde_json::from_str::(r#""0x252e5966""#).unwrap()) // The selector of "getPubdataPriceMode()" + .data(get_pubdata_price_mode_selector()) .build(), ) .await From 3fd04b14881c5b69f9a46ccedebc2f1ea9263c0a Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Fri, 23 Feb 2024 11:36:25 +0200 Subject: [PATCH 046/106] chore(docker): Exclude trusted_setup from .dockerignore (#1224) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Excludes `trusted_setup.json` from .dockerignore so witness generator docker image can be build ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 8268fb1049e6..c9c4673e3adc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -39,3 +39,4 @@ contracts/.git !bellman-cuda !prover/vk_setup_data_generator_server_fri/data/ !.github/release-please/manifest.json +!trusted_setup.json From a1c866c9fc9c6e6ceed9a1cc0b39e0fade29ecfa Mon Sep 17 00:00:00 2001 From: Lech <88630083+Artemka374@users.noreply.github.com> Date: Fri, 23 Feb 2024 11:45:43 +0200 Subject: [PATCH 047/106] feat: Integration tests enhancement for L1 (#1209) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Make tests send transactions subsequently, use Promise.all() only on waiting receipt. Add more logging Increase gas price by 30% to prevent test timeout ## Why ❔ Integrationg tests for L1 are not working properly. ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- .../tests/ts-integration/src/context-owner.ts | 142 ++++++++++-------- core/tests/ts-integration/src/helpers.ts | 2 +- 2 files changed, 81 insertions(+), 63 deletions(-) diff --git a/core/tests/ts-integration/src/context-owner.ts b/core/tests/ts-integration/src/context-owner.ts index f4f6fa0d05a1..4f71df548e95 100644 --- a/core/tests/ts-integration/src/context-owner.ts +++ b/core/tests/ts-integration/src/context-owner.ts @@ -241,20 +241,23 @@ export class TestContextOwner { if (!l2ETHAmountToDeposit.isZero()) { // Given that we've already sent a number of transactions, // we have to correctly send nonce. - const depositHandle = this.mainSyncWallet - .deposit({ - token: zksync.utils.ETH_ADDRESS, - amount: l2ETHAmountToDeposit, - overrides: { - nonce: nonce++, - gasPrice - } - }) - .then((tx) => { - const amount = ethers.utils.formatEther(l2ETHAmountToDeposit); - this.reporter.debug(`Sent ETH deposit. Nonce ${tx.nonce}, amount: ${amount}, hash: ${tx.hash}`); - tx.wait(); - }); + const txDeposit = await this.mainSyncWallet.deposit({ + token: zksync.utils.ETH_ADDRESS, + amount: l2ETHAmountToDeposit, + overrides: { + nonce: nonce++, + gasPrice + } + }); + const amount = ethers.utils.formatEther(l2ETHAmountToDeposit); + this.reporter.debug( + `Sent ETH deposit. Nonce ${txDeposit.nonce}, amount: ${amount}, hash: ${txDeposit.hash}` + ); + + let depositHandle = txDeposit.wait().then((tx) => { + this.reporter.debug(`Obtained receipt for ETH deposit. Amount: ${amount}, hash: ${tx.transactionHash}`); + return tx; + }); // Add this promise to the list of L1 tx promises. l1TxPromises.push(depositHandle); @@ -267,36 +270,41 @@ export class TestContextOwner { // Mint ERC20. const l1Erc20ABI = ['function mint(address to, uint256 amount)']; const l1Erc20Contract = new ethers.Contract(erc20Token, l1Erc20ABI, this.mainEthersWallet); - const erc20MintPromise = l1Erc20Contract - .mint(this.mainSyncWallet.address, erc20MintAmount, { + + let txMint = await l1Erc20Contract.mint(this.mainSyncWallet.address, erc20MintAmount, { + nonce: nonce++, + gasPrice + }); + this.reporter.debug(`Sent ERC20 mint transaction. Hash: ${txMint.hash}, nonce ${txMint.nonce}`); + + const erc20MintPromise = txMint.wait().then((tx: any) => { + this.reporter.debug(`Obtained receipt for ERC20 mint transaction. Hash: ${tx.transactionHash}`); + return tx; + }); + + // Deposit ERC20. + let txDepositErc20 = await this.mainSyncWallet.deposit({ + token: erc20Token, + amount: l2erc20DepositAmount, + approveERC20: true, + approveOverrides: { nonce: nonce++, gasPrice - }) - .then((tx: any) => { - this.reporter.debug(`Sent ERC20 mint transaction. Hash: ${tx.hash}, nonce ${tx.nonce}`); - return tx.wait(); - }); + }, + overrides: { + nonce: nonce++, + gasPrice + } + }); + this.reporter.debug( + `Sent ERC20 deposit transaction. Hash: ${txDepositErc20.hash}, nonce: ${txDepositErc20.nonce}` + ); - // Deposit ERC20. - const erc20DepositPromise = this.mainSyncWallet - .deposit({ - token: erc20Token, - amount: l2erc20DepositAmount, - approveERC20: true, - approveOverrides: { - nonce: nonce++, - gasPrice - }, - overrides: { - nonce: nonce++, - gasPrice - } - }) - .then((tx) => { - // Note: there is an `approve` tx, not listed here. - this.reporter.debug(`Sent ERC20 deposit transaction. Hash: ${tx.hash}, nonce: ${tx.nonce}`); - return tx.wait(); - }); + const erc20DepositPromise = txDepositErc20.wait().then((tx: any) => { + // Note: there is an `approve` tx, not listed here. + this.reporter?.debug(`Obtained receipt for ERC20 deposit transaction. Hash: ${tx.transactionHash}`); + return tx; + }); // Send ETH on L1. const ethTransfers = await sendTransfers( @@ -328,13 +336,8 @@ export class TestContextOwner { this.reporter.debug(`Sent ${l1TxPromises.length} initial transactions on L1`); - if (this.env.network === 'localhost') { - await Promise.all(l1TxPromises); - } else { - for (const promise of l1TxPromises) { - await promise; - } - } + await Promise.all(l1TxPromises); + this.reporter.finishAction(); } @@ -447,7 +450,13 @@ export async function sendTransfers( : new ethers.Contract(token, zksync.utils.IERC20, wallet); const startNonce = overrideStartNonce ?? (await wallet.getTransactionCount()); reporter?.debug(`Sending transfers. Token address is ${token}`); - const txPromises = Array.from(Object.values(wallets)).map((testWalletPK, index) => { + + const walletsPK = Array.from(Object.values(wallets)); + + const txPromises: Promise[] = []; + + for (let index = 0; index < walletsPK.length; index++) { + const testWalletPK = walletsPK[index]; if (token == zksync.utils.ETH_ADDRESS) { const tx = { to: ethers.utils.computeAddress(testWalletPK), @@ -457,31 +466,40 @@ export async function sendTransfers( }; reporter?.debug(`Inititated ETH transfer with nonce: ${tx.nonce}`); - return wallet.sendTransaction(tx).then((tx) => { - reporter?.debug(`Sent ETH transfer tx: ${tx.hash}, nonce: ${tx.nonce}`); - return tx.wait(); - }); + let transactionResponse = await wallet.sendTransaction(tx); + reporter?.debug(`Sent ETH transfer tx: ${transactionResponse.hash}, nonce: ${transactionResponse.nonce}`); + + txPromises.push( + transactionResponse.wait().then((tx) => { + reporter?.debug(`Obtained receipt for ETH transfer tx: ${tx.transactionHash} `); + return tx; + }) + ); } else { const txNonce = startNonce + index; - const tx = erc20Contract.transfer(ethers.utils.computeAddress(testWalletPK), value, { + reporter?.debug(`Inititated ERC20 transfer with nonce: ${txNonce}`); + const tx = await erc20Contract.transfer(ethers.utils.computeAddress(testWalletPK), value, { nonce: txNonce, gasPrice }); - reporter?.debug(`Inititated ERC20 transfer with nonce: ${txNonce}`); - // @ts-ignore - return tx.then((tx) => { - reporter?.debug(`Sent ERC20 transfer tx: ${tx.hash}, nonce: ${tx.nonce}`); - return tx.wait(); - }); + reporter?.debug(`Sent ERC20 transfer tx: ${tx.hash}, nonce: ${tx.nonce}`); + + txPromises.push( + // @ts-ignore + tx.wait().then((tx) => { + reporter?.debug(`Obtained receipt for ERC20 transfer tx: ${tx.transactionHash}`); + return tx; + }) + ); } - }); + } + reporter?.debug( `Initiated ${txPromises.length} transfers. Nonce range is ${startNonce} - ${startNonce + txPromises.length - 1}` ); return txPromises; } - /** * Sends all the Ether from one account to another. * Can work both with L1 and L2 wallets. diff --git a/core/tests/ts-integration/src/helpers.ts b/core/tests/ts-integration/src/helpers.ts index 1b6d1dff477b..4e2c15802eb8 100644 --- a/core/tests/ts-integration/src/helpers.ts +++ b/core/tests/ts-integration/src/helpers.ts @@ -103,5 +103,5 @@ export async function waitUntilBlockFinalized(wallet: zksync.Wallet, blockNumber export async function scaledGasPrice(wallet: ethers.Wallet | zksync.Wallet): Promise { const gasPrice = await wallet.getGasPrice(); // Increase by 40%. - return gasPrice.mul(140).div(100); + return gasPrice.mul(170).div(100); } From 63d1f529ca8f2125e6effa8bc3baef45bc7ef602 Mon Sep 17 00:00:00 2001 From: perekopskiy <53865202+perekopskiy@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:34:18 +0200 Subject: [PATCH 048/106] feat(vm): integrate new vm version (#1215) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ Integrates new VM version ## Why ❔ ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- core/lib/commitment_utils/src/lib.rs | 4 +- core/lib/contracts/src/lib.rs | 14 ++ core/lib/multivm/src/glue/history_mode.rs | 22 +- core/lib/multivm/src/glue/tracers/mod.rs | 23 +- .../src/glue/types/vm/storage_query.rs | 9 + core/lib/multivm/src/lib.rs | 2 +- .../multivm/src/tracers/call_tracer/mod.rs | 1 + .../src/tracers/call_tracer/vm_1_4_1/mod.rs | 209 ++++++++++++++++++ .../multivm/src/tracers/multivm_dispatcher.rs | 10 +- .../src/tracers/storage_invocation/mod.rs | 1 + .../storage_invocation/vm_1_4_1/mod.rs | 35 +++ core/lib/multivm/src/tracers/validator/mod.rs | 1 + .../src/tracers/validator/vm_1_4_1/mod.rs | 201 +++++++++++++++++ .../src/tracers/validator/vm_latest/mod.rs | 10 +- core/lib/multivm/src/utils.rs | 65 ++++-- core/lib/multivm/src/versions/mod.rs | 1 + .../vm_1_4_1/implementation/snapshots.rs | 10 +- core/lib/multivm/src/versions/vm_1_4_1/mod.rs | 2 - .../vm_1_4_1/tracers/pubdata_tracer.rs | 17 -- .../src/versions/vm_1_4_1/tracers/refunds.rs | 2 +- .../src/versions/vm_1_4_1/utils/fee.rs | 36 +-- core/lib/multivm/src/versions/vm_1_4_1/vm.rs | 4 +- .../vm_latest/implementation/execution.rs | 8 +- .../versions/vm_latest/implementation/gas.rs | 2 +- .../vm_latest/implementation/statistics.rs | 2 +- .../vm_latest/tests/tester/inner_state.rs | 2 +- .../src/versions/vm_latest/utils/fee.rs | 36 +-- core/lib/multivm/src/versions/vm_latest/vm.rs | 4 +- core/lib/multivm/src/vm_instance.rs | 10 +- core/lib/types/src/protocol_version.rs | 7 +- core/lib/types/src/vm_version.rs | 3 +- .../api_server/execution_sandbox/tracers.rs | 2 +- .../src/api_server/tx_sender/mod.rs | 7 +- .../ts-integration/tests/api/web3.test.ts | 22 +- .../fee_estimate.yul/fee_estimate.yul.zbin | Bin 0 -> 65888 bytes .../vm_1_4_2/gas_test.yul/gas_test.yul.zbin | Bin 0 -> 64352 bytes .../playground_batch.yul.zbin | Bin 0 -> 66144 bytes .../proved_batch.yul/proved_batch.yul.zbin | Bin 0 -> 64928 bytes 38 files changed, 635 insertions(+), 149 deletions(-) create mode 100644 core/lib/multivm/src/tracers/call_tracer/vm_1_4_1/mod.rs create mode 100644 core/lib/multivm/src/tracers/storage_invocation/vm_1_4_1/mod.rs create mode 100644 core/lib/multivm/src/tracers/validator/vm_1_4_1/mod.rs create mode 100644 etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin create mode 100644 etc/multivm_bootloaders/vm_1_4_2/gas_test.yul/gas_test.yul.zbin create mode 100644 etc/multivm_bootloaders/vm_1_4_2/playground_batch.yul/playground_batch.yul.zbin create mode 100644 etc/multivm_bootloaders/vm_1_4_2/proved_batch.yul/proved_batch.yul.zbin diff --git a/core/lib/commitment_utils/src/lib.rs b/core/lib/commitment_utils/src/lib.rs index cfdfa23e81d5..c420233369f4 100644 --- a/core/lib/commitment_utils/src/lib.rs +++ b/core/lib/commitment_utils/src/lib.rs @@ -24,7 +24,7 @@ pub fn events_queue_commitment( .collect(), ), )), - VmVersion::Vm1_4_1 => Some(H256( + VmVersion::Vm1_4_1 | VmVersion::Vm1_4_2 => Some(H256( zkevm_test_harness_1_4_1::witness::utils::events_queue_commitment_fixed( &events_queue .iter() @@ -55,7 +55,7 @@ pub fn bootloader_initial_content_commitment( &full_bootloader_memory, ), )), - VmVersion::Vm1_4_1 => Some(H256( + VmVersion::Vm1_4_1 | VmVersion::Vm1_4_2 => Some(H256( zkevm_test_harness_1_4_1::witness::utils::initial_heap_content_commitment_fixed( &full_bootloader_memory, ), diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 065008d5dbce..fe390b4cd9e2 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -312,6 +312,13 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } + pub fn playground_post_1_4_2() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_1_4_2/playground_batch.yul/playground_batch.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + pub fn estimate_gas_pre_virtual_blocks() -> Self { let bootloader_bytecode = read_zbin_bytecode( "etc/multivm_bootloaders/vm_1_3_2/fee_estimate.yul/fee_estimate.yul.zbin", @@ -354,6 +361,13 @@ impl BaseSystemContracts { BaseSystemContracts::load_with_bootloader(bootloader_bytecode) } + pub fn estimate_gas_post_1_4_2() -> Self { + let bootloader_bytecode = read_zbin_bytecode( + "etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin", + ); + BaseSystemContracts::load_with_bootloader(bootloader_bytecode) + } + pub fn hashes(&self) -> BaseSystemContractsHashes { BaseSystemContractsHashes { bootloader: self.bootloader.hash, diff --git a/core/lib/multivm/src/glue/history_mode.rs b/core/lib/multivm/src/glue/history_mode.rs index f820477c10a5..45de90fc446d 100644 --- a/core/lib/multivm/src/glue/history_mode.rs +++ b/core/lib/multivm/src/glue/history_mode.rs @@ -8,13 +8,15 @@ pub trait HistoryMode: + GlueInto + GlueInto + GlueInto + + GlueInto { type VmM6Mode: crate::vm_m6::HistoryMode; type Vm1_3_2Mode: crate::vm_1_3_2::HistoryMode; type VmVirtualBlocksMode: crate::vm_virtual_blocks::HistoryMode; type VmVirtualBlocksRefundsEnhancement: crate::vm_refunds_enhancement::HistoryMode; type VmBoojumIntegration: crate::vm_boojum_integration::HistoryMode; - type Vm1_4_1: crate::vm_latest::HistoryMode; + type Vm1_4_1: crate::vm_1_4_1::HistoryMode; + type Vm1_4_2: crate::vm_latest::HistoryMode; } impl GlueFrom for crate::vm_m6::HistoryEnabled { @@ -47,6 +49,12 @@ impl GlueFrom for crate::vm_boojum_integration } } +impl GlueFrom for crate::vm_1_4_1::HistoryEnabled { + fn glue_from(_: crate::vm_latest::HistoryEnabled) -> Self { + Self + } +} + impl GlueFrom for crate::vm_m6::HistoryDisabled { fn glue_from(_: crate::vm_latest::HistoryDisabled) -> Self { Self @@ -79,13 +87,20 @@ impl GlueFrom for crate::vm_boojum_integratio } } +impl GlueFrom for crate::vm_1_4_1::HistoryDisabled { + fn glue_from(_: crate::vm_latest::HistoryDisabled) -> Self { + Self + } +} + impl HistoryMode for crate::vm_latest::HistoryEnabled { type VmM6Mode = crate::vm_m6::HistoryEnabled; type Vm1_3_2Mode = crate::vm_1_3_2::HistoryEnabled; type VmVirtualBlocksMode = crate::vm_virtual_blocks::HistoryEnabled; type VmVirtualBlocksRefundsEnhancement = crate::vm_refunds_enhancement::HistoryEnabled; type VmBoojumIntegration = crate::vm_boojum_integration::HistoryEnabled; - type Vm1_4_1 = crate::vm_latest::HistoryEnabled; + type Vm1_4_1 = crate::vm_1_4_1::HistoryEnabled; + type Vm1_4_2 = crate::vm_latest::HistoryEnabled; } impl HistoryMode for crate::vm_latest::HistoryDisabled { @@ -94,5 +109,6 @@ impl HistoryMode for crate::vm_latest::HistoryDisabled { type VmVirtualBlocksMode = crate::vm_virtual_blocks::HistoryDisabled; type VmVirtualBlocksRefundsEnhancement = crate::vm_refunds_enhancement::HistoryDisabled; type VmBoojumIntegration = crate::vm_boojum_integration::HistoryDisabled; - type Vm1_4_1 = crate::vm_latest::HistoryDisabled; + type Vm1_4_1 = crate::vm_1_4_1::HistoryDisabled; + type Vm1_4_2 = crate::vm_latest::HistoryDisabled; } diff --git a/core/lib/multivm/src/glue/tracers/mod.rs b/core/lib/multivm/src/glue/tracers/mod.rs index 3ca26892113c..46a7acf0665f 100644 --- a/core/lib/multivm/src/glue/tracers/mod.rs +++ b/core/lib/multivm/src/glue/tracers/mod.rs @@ -41,6 +41,7 @@ pub trait MultiVMTracer: + IntoVmVirtualBlocksTracer + IntoVmRefundsEnhancementTracer + IntoVmBoojumIntegrationTracer + + IntoVm1_4_1IntegrationTracer + IntoOldVmTracer { fn into_tracer_pointer(self) -> MultiVmTracerPointer @@ -52,7 +53,7 @@ pub trait MultiVMTracer: } pub trait IntoLatestTracer { - fn latest(&self) -> crate::vm_latest::TracerPointer; + fn latest(&self) -> crate::vm_latest::TracerPointer; } pub trait IntoVmVirtualBlocksTracer { @@ -73,6 +74,10 @@ pub trait IntoVmBoojumIntegrationTracer { ) -> Box>; } +pub trait IntoVm1_4_1IntegrationTracer { + fn vm_1_4_1(&self) -> Box>; +} + /// Into tracers for old VM versions. /// Even though number of tracers is limited, we still need to have this trait to be able to convert /// tracers to old VM tracers. @@ -89,9 +94,9 @@ impl IntoLatestTracer for T where S: WriteStorage, H: HistoryMode, - T: crate::vm_latest::VmTracer + Clone + 'static, + T: crate::vm_latest::VmTracer + Clone + 'static, { - fn latest(&self) -> crate::vm_latest::TracerPointer { + fn latest(&self) -> crate::vm_latest::TracerPointer { Box::new(self.clone()) } } @@ -138,6 +143,17 @@ where } } +impl IntoVm1_4_1IntegrationTracer for T +where + S: WriteStorage, + H: HistoryMode, + T: crate::vm_1_4_1::VmTracer + Clone + 'static, +{ + fn vm_1_4_1(&self) -> Box> { + Box::new(self.clone()) + } +} + impl MultiVMTracer for T where S: WriteStorage, @@ -146,6 +162,7 @@ where + IntoVmVirtualBlocksTracer + IntoVmRefundsEnhancementTracer + IntoVmBoojumIntegrationTracer + + IntoVm1_4_1IntegrationTracer + IntoOldVmTracer, { } diff --git a/core/lib/multivm/src/glue/types/vm/storage_query.rs b/core/lib/multivm/src/glue/types/vm/storage_query.rs index 21a10947e09b..19c543954e35 100644 --- a/core/lib/multivm/src/glue/types/vm/storage_query.rs +++ b/core/lib/multivm/src/glue/types/vm/storage_query.rs @@ -56,6 +56,15 @@ impl GlueFrom for St } } +impl GlueFrom for StorageLogQuery { + fn glue_from(value: crate::vm_1_4_1::utils::logs::StorageLogQuery) -> Self { + Self { + log_query: value.log_query.glue_into(), + log_type: value.log_type, + } + } +} + impl GlueFrom for StorageLogQuery { fn glue_from(value: crate::vm_latest::utils::logs::StorageLogQuery) -> Self { Self { diff --git a/core/lib/multivm/src/lib.rs b/core/lib/multivm/src/lib.rs index aa55026d88fe..b8278257f526 100644 --- a/core/lib/multivm/src/lib.rs +++ b/core/lib/multivm/src/lib.rs @@ -7,7 +7,7 @@ pub use zkevm_test_harness_1_4_1 as zkevm_test_harness_latest; pub use zksync_types::vm_version::VmVersion; pub use self::versions::{ - vm_1_3_2, vm_boojum_integration, vm_latest, vm_m5, vm_m6, vm_refunds_enhancement, + vm_1_3_2, vm_1_4_1, vm_boojum_integration, vm_latest, vm_m5, vm_m6, vm_refunds_enhancement, vm_virtual_blocks, }; pub use crate::{ diff --git a/core/lib/multivm/src/tracers/call_tracer/mod.rs b/core/lib/multivm/src/tracers/call_tracer/mod.rs index b3a98902f4b9..989db54d968f 100644 --- a/core/lib/multivm/src/tracers/call_tracer/mod.rs +++ b/core/lib/multivm/src/tracers/call_tracer/mod.rs @@ -6,6 +6,7 @@ use zksync_types::vm_trace::Call; use crate::{glue::tracers::IntoOldVmTracer, tracers::call_tracer::metrics::CALL_METRICS}; mod metrics; +pub mod vm_1_4_1; pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_refunds_enhancement; diff --git a/core/lib/multivm/src/tracers/call_tracer/vm_1_4_1/mod.rs b/core/lib/multivm/src/tracers/call_tracer/vm_1_4_1/mod.rs new file mode 100644 index 000000000000..54809168fca8 --- /dev/null +++ b/core/lib/multivm/src/tracers/call_tracer/vm_1_4_1/mod.rs @@ -0,0 +1,209 @@ +use zk_evm_1_4_1::{ + tracing::{AfterExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ + FarCallABI, FatPointer, Opcode, RetOpcode, CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER, + RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER, + }, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::CONTRACT_DEPLOYER_ADDRESS; +use zksync_types::{ + vm_trace::{Call, CallType}, + zk_evm_types::FarCallOpcode, + U256, +}; + +use crate::{ + glue::GlueInto, + interface::{ + tracer::VmExecutionStopReason, traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + VmRevertReason, + }, + tracers::call_tracer::CallTracer, + vm_1_4_1::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState}, +}; + +impl DynTracer> for CallTracer { + fn after_execution( + &mut self, + state: VmLocalStateData<'_>, + data: AfterExecutionData, + memory: &SimpleMemory, + _storage: StoragePtr, + ) { + match data.opcode.variant.opcode { + Opcode::NearCall(_) => { + self.increase_near_call_count(); + } + Opcode::FarCall(far_call) => { + // We use parent gas for properly calculating gas used in the trace. + let current_ergs = state.vm_local_state.callstack.current.ergs_remaining; + let parent_gas = state + .vm_local_state + .callstack + .inner + .last() + .map(|call| call.ergs_remaining + current_ergs) + .unwrap_or(current_ergs); + + let mut current_call = Call { + r#type: CallType::Call(far_call.glue_into()), + gas: 0, + parent_gas, + ..Default::default() + }; + + self.handle_far_call_op_code_vm_1_4_1(state, memory, &mut current_call); + self.push_call_and_update_stats(current_call, 0); + } + Opcode::Ret(ret_code) => { + self.handle_ret_op_code_vm_1_4_1(state, memory, ret_code); + } + _ => {} + }; + } +} + +impl VmTracer for CallTracer { + fn after_vm_execution( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &BootloaderState, + _stop_reason: VmExecutionStopReason, + ) { + self.store_result() + } +} + +impl CallTracer { + fn handle_far_call_op_code_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + current_call: &mut Call, + ) { + let current = state.vm_local_state.callstack.current; + // All calls from the actual users are mimic calls, + // so we need to check that the previous call was to the deployer. + // Actually it's a call of the constructor. + // And at this stage caller is user and callee is deployed contract. + let call_type = if let CallType::Call(far_call) = current_call.r#type { + if matches!(far_call, FarCallOpcode::Mimic) { + let previous_caller = state + .vm_local_state + .callstack + .inner + .last() + .map(|call| call.this_address) + // Actually it's safe to just unwrap here, because we have at least one call in the stack + // But i want to be sure that we will not have any problems in the future + .unwrap_or(current.this_address); + if previous_caller == CONTRACT_DEPLOYER_ADDRESS { + CallType::Create + } else { + CallType::Call(far_call) + } + } else { + CallType::Call(far_call) + } + } else { + unreachable!() + }; + let calldata = if current.code_page.0 == 0 || current.ergs_remaining == 0 { + vec![] + } else { + let packed_abi = + state.vm_local_state.registers[CALL_IMPLICIT_CALLDATA_FAT_PTR_REGISTER as usize]; + assert!(packed_abi.is_pointer); + let far_call_abi = FarCallABI::from_u256(packed_abi.value); + memory.read_unaligned_bytes( + far_call_abi.memory_quasi_fat_pointer.memory_page as usize, + far_call_abi.memory_quasi_fat_pointer.start as usize, + far_call_abi.memory_quasi_fat_pointer.length as usize, + ) + }; + + current_call.input = calldata; + current_call.r#type = call_type; + current_call.from = current.msg_sender; + current_call.to = current.this_address; + current_call.value = U256::from(current.context_u128_value); + current_call.gas = current.ergs_remaining; + } + + fn save_output_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + ret_opcode: RetOpcode, + current_call: &mut Call, + ) { + let fat_data_pointer = + state.vm_local_state.registers[RET_IMPLICIT_RETURNDATA_PARAMS_REGISTER as usize]; + + // if `fat_data_pointer` is not a pointer then there is no output + let output = if fat_data_pointer.is_pointer { + let fat_data_pointer = FatPointer::from_u256(fat_data_pointer.value); + if !fat_data_pointer.is_trivial() { + Some(memory.read_unaligned_bytes( + fat_data_pointer.memory_page as usize, + fat_data_pointer.start as usize, + fat_data_pointer.length as usize, + )) + } else { + None + } + } else { + None + }; + + match ret_opcode { + RetOpcode::Ok => { + current_call.output = output.unwrap_or_default(); + } + RetOpcode::Revert => { + if let Some(output) = output { + current_call.revert_reason = + Some(VmRevertReason::from(output.as_slice()).to_string()); + } else { + current_call.revert_reason = Some("Unknown revert reason".to_string()); + } + } + RetOpcode::Panic => { + current_call.error = Some("Panic".to_string()); + } + } + } + + fn handle_ret_op_code_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + memory: &SimpleMemory, + ret_opcode: RetOpcode, + ) { + let Some(mut current_call) = self.stack.pop() else { + return; + }; + + if current_call.near_calls_after > 0 { + current_call.near_calls_after -= 1; + self.push_call_and_update_stats(current_call.farcall, current_call.near_calls_after); + return; + } + + current_call.farcall.gas_used = current_call + .farcall + .parent_gas + .saturating_sub(state.vm_local_state.callstack.current.ergs_remaining); + + self.save_output_vm_1_4_1(state, memory, ret_opcode, &mut current_call.farcall); + + // If there is a parent call, push the current call to it + // Otherwise, push the current call to the stack, because it's the top level call + if let Some(parent_call) = self.stack.last_mut() { + parent_call.farcall.calls.push(current_call.farcall); + } else { + self.push_call_and_update_stats(current_call.farcall, current_call.near_calls_after); + } + } +} diff --git a/core/lib/multivm/src/tracers/multivm_dispatcher.rs b/core/lib/multivm/src/tracers/multivm_dispatcher.rs index 0e8585884fa5..b616c571f77c 100644 --- a/core/lib/multivm/src/tracers/multivm_dispatcher.rs +++ b/core/lib/multivm/src/tracers/multivm_dispatcher.rs @@ -30,7 +30,7 @@ impl Default for TracerDispatcher { } impl From> - for crate::vm_latest::TracerDispatcher + for crate::vm_latest::TracerDispatcher { fn from(value: TracerDispatcher) -> Self { Self::new(value.tracers.into_iter().map(|x| x.latest()).collect()) @@ -51,6 +51,14 @@ impl From> } } +impl From> + for crate::vm_1_4_1::TracerDispatcher +{ + fn from(value: TracerDispatcher) -> Self { + Self::new(value.tracers.into_iter().map(|x| x.vm_1_4_1()).collect()) + } +} + impl From> for crate::vm_refunds_enhancement::TracerDispatcher { diff --git a/core/lib/multivm/src/tracers/storage_invocation/mod.rs b/core/lib/multivm/src/tracers/storage_invocation/mod.rs index db4e936e0112..210a175507b9 100644 --- a/core/lib/multivm/src/tracers/storage_invocation/mod.rs +++ b/core/lib/multivm/src/tracers/storage_invocation/mod.rs @@ -1,5 +1,6 @@ use crate::{glue::tracers::IntoOldVmTracer, tracers::old_tracers::OldTracers}; +pub mod vm_1_4_1; pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_refunds_enhancement; diff --git a/core/lib/multivm/src/tracers/storage_invocation/vm_1_4_1/mod.rs b/core/lib/multivm/src/tracers/storage_invocation/vm_1_4_1/mod.rs new file mode 100644 index 000000000000..be3a30adb1d4 --- /dev/null +++ b/core/lib/multivm/src/tracers/storage_invocation/vm_1_4_1/mod.rs @@ -0,0 +1,35 @@ +use zksync_state::WriteStorage; + +use crate::{ + interface::{ + tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + Halt, + }, + tracers::storage_invocation::StorageInvocations, + vm_1_4_1::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState}, +}; + +impl DynTracer> for StorageInvocations {} + +impl VmTracer for StorageInvocations { + fn finish_cycle( + &mut self, + state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + let current = state + .storage + .storage + .get_ptr() + .borrow() + .missed_storage_invocations(); + + if current >= self.limit { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::TracerCustom("Storage invocations limit reached".to_string()), + )); + } + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/tracers/validator/mod.rs b/core/lib/multivm/src/tracers/validator/mod.rs index c56424f3013e..caf9dee30c9d 100644 --- a/core/lib/multivm/src/tracers/validator/mod.rs +++ b/core/lib/multivm/src/tracers/validator/mod.rs @@ -19,6 +19,7 @@ use crate::{ }; mod types; +mod vm_1_4_1; mod vm_boojum_integration; mod vm_latest; mod vm_refunds_enhancement; diff --git a/core/lib/multivm/src/tracers/validator/vm_1_4_1/mod.rs b/core/lib/multivm/src/tracers/validator/vm_1_4_1/mod.rs new file mode 100644 index 000000000000..81d885fa788e --- /dev/null +++ b/core/lib/multivm/src/tracers/validator/vm_1_4_1/mod.rs @@ -0,0 +1,201 @@ +use zk_evm_1_4_1::{ + tracing::{BeforeExecutionData, VmLocalStateData}, + zkevm_opcode_defs::{ContextOpcode, FarCallABI, LogOpcode, Opcode}, +}; +use zksync_state::{StoragePtr, WriteStorage}; +use zksync_system_constants::KECCAK256_PRECOMPILE_ADDRESS; +use zksync_types::{ + get_code_key, vm_trace::ViolatedValidationRule, AccountTreeId, StorageKey, H256, +}; +use zksync_utils::{h256_to_account_address, u256_to_account_address, u256_to_h256}; + +use crate::{ + interface::{ + traits::tracers::dyn_tracers::vm_1_4_1::DynTracer, + types::tracer::{TracerExecutionStatus, TracerExecutionStopReason}, + Halt, + }, + tracers::validator::{ + types::{NewTrustedValidationItems, ValidationTracerMode}, + ValidationRoundResult, ValidationTracer, + }, + vm_1_4_1::{ + tracers::utils::{ + computational_gas_price, get_calldata_page_via_abi, print_debug_if_needed, VmHook, + }, + BootloaderState, SimpleMemory, VmTracer, ZkSyncVmState, + }, + HistoryMode, +}; + +impl ValidationTracer { + fn check_user_restrictions_vm_1_4_1( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + storage: StoragePtr, + ) -> ValidationRoundResult { + if self.computational_gas_used > self.computational_gas_limit { + return Err(ViolatedValidationRule::TookTooManyComputationalGas( + self.computational_gas_limit, + )); + } + + let opcode_variant = data.opcode.variant; + match opcode_variant.opcode { + Opcode::FarCall(_) => { + let packed_abi = data.src0_value.value; + let call_destination_value = data.src1_value.value; + + let called_address = u256_to_account_address(&call_destination_value); + let far_call_abi = FarCallABI::from_u256(packed_abi); + + if called_address == KECCAK256_PRECOMPILE_ADDRESS + && far_call_abi.memory_quasi_fat_pointer.length == 64 + { + let calldata_page = get_calldata_page_via_abi( + &far_call_abi, + state.vm_local_state.callstack.current.base_memory_page, + ); + let calldata = memory.read_unaligned_bytes( + calldata_page as usize, + far_call_abi.memory_quasi_fat_pointer.start as usize, + 64, + ); + + let slot_to_add = + self.slot_to_add_from_keccak_call(&calldata, self.user_address); + + if let Some(slot) = slot_to_add { + return Ok(NewTrustedValidationItems { + new_allowed_slots: vec![slot], + ..Default::default() + }); + } + } else if called_address != self.user_address { + let code_key = get_code_key(&called_address); + let code = storage.borrow_mut().read_value(&code_key); + + if code == H256::zero() { + // The users are not allowed to call contracts with no code + return Err(ViolatedValidationRule::CalledContractWithNoCode( + called_address, + )); + } + } + } + Opcode::Context(context) => { + match context { + ContextOpcode::Meta => { + return Err(ViolatedValidationRule::TouchedUnallowedContext); + } + ContextOpcode::ErgsLeft => { + // TODO (SMA-1168): implement the correct restrictions for the gas left opcode. + } + _ => {} + } + } + Opcode::Log(LogOpcode::StorageRead) => { + let key = data.src0_value.value; + let this_address = state.vm_local_state.callstack.current.this_address; + let msg_sender = state.vm_local_state.callstack.current.msg_sender; + + if !self.is_allowed_storage_read(storage.clone(), this_address, key, msg_sender) { + return Err(ViolatedValidationRule::TouchedUnallowedStorageSlots( + this_address, + key, + )); + } + + if self.trusted_address_slots.contains(&(this_address, key)) { + let storage_key = + StorageKey::new(AccountTreeId::new(this_address), u256_to_h256(key)); + + let value = storage.borrow_mut().read_value(&storage_key); + + return Ok(NewTrustedValidationItems { + new_trusted_addresses: vec![h256_to_account_address(&value)], + ..Default::default() + }); + } + } + _ => {} + } + + Ok(Default::default()) + } +} + +impl DynTracer> + for ValidationTracer +{ + fn before_execution( + &mut self, + state: VmLocalStateData<'_>, + data: BeforeExecutionData, + memory: &SimpleMemory, + storage: StoragePtr, + ) { + // For now, we support only validations for users. + if let ValidationTracerMode::UserTxValidation = self.validation_mode { + self.computational_gas_used = self + .computational_gas_used + .saturating_add(computational_gas_price(state, &data)); + + let validation_round_result = + self.check_user_restrictions_vm_1_4_1(state, data, memory, storage); + self.process_validation_round_result(validation_round_result); + } + + let hook = VmHook::from_opcode_memory(&state, &data); + print_debug_if_needed(&hook, &state, memory); + + let current_mode = self.validation_mode; + match (current_mode, hook) { + (ValidationTracerMode::NoValidation, VmHook::AccountValidationEntered) => { + // Account validation can be entered when there is no prior validation (i.e. "nested" validations are not allowed) + self.validation_mode = ValidationTracerMode::UserTxValidation; + } + (ValidationTracerMode::NoValidation, VmHook::PaymasterValidationEntered) => { + // Paymaster validation can be entered when there is no prior validation (i.e. "nested" validations are not allowed) + self.validation_mode = ValidationTracerMode::PaymasterTxValidation; + } + (_, VmHook::AccountValidationEntered | VmHook::PaymasterValidationEntered) => { + panic!( + "Unallowed transition inside the validation tracer. Mode: {:#?}, hook: {:#?}", + self.validation_mode, hook + ); + } + (_, VmHook::NoValidationEntered) => { + // Validation can be always turned off + self.validation_mode = ValidationTracerMode::NoValidation; + } + (_, VmHook::ValidationStepEndeded) => { + // The validation step has ended. + self.should_stop_execution = true; + } + (_, _) => { + // The hook is not relevant to the validation tracer. Ignore. + } + } + } +} + +impl VmTracer for ValidationTracer { + fn finish_cycle( + &mut self, + _state: &mut ZkSyncVmState, + _bootloader_state: &mut BootloaderState, + ) -> TracerExecutionStatus { + if self.should_stop_execution { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Finish); + } + if let Some(result) = self.result.get() { + return TracerExecutionStatus::Stop(TracerExecutionStopReason::Abort( + Halt::TracerCustom(format!("Validation error: {:#?}", result)), + )); + } + TracerExecutionStatus::Continue + } +} diff --git a/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs b/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs index 095f1a20b38b..a2096ee68961 100644 --- a/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs +++ b/core/lib/multivm/src/tracers/validator/vm_latest/mod.rs @@ -33,7 +33,7 @@ impl ValidationTracer { &mut self, state: VmLocalStateData<'_>, data: BeforeExecutionData, - memory: &SimpleMemory, + memory: &SimpleMemory, storage: StoragePtr, ) -> ValidationRoundResult { if self.computational_gas_used > self.computational_gas_limit { @@ -127,14 +127,14 @@ impl ValidationTracer { } } -impl DynTracer> +impl DynTracer> for ValidationTracer { fn before_execution( &mut self, state: VmLocalStateData<'_>, data: BeforeExecutionData, - memory: &SimpleMemory, + memory: &SimpleMemory, storage: StoragePtr, ) { // For now, we support only validations for users. @@ -182,10 +182,10 @@ impl DynTracer> } } -impl VmTracer for ValidationTracer { +impl VmTracer for ValidationTracer { fn finish_cycle( &mut self, - _state: &mut ZkSyncVmState, + _state: &mut ZkSyncVmState, _bootloader_state: &mut BootloaderState, ) -> TracerExecutionStatus { if self.should_stop_execution { diff --git a/core/lib/multivm/src/utils.rs b/core/lib/multivm/src/utils.rs index 1488ee3df19d..9f5ae5540c39 100644 --- a/core/lib/multivm/src/utils.rs +++ b/core/lib/multivm/src/utils.rs @@ -1,4 +1,7 @@ -use zksync_types::{fee_model::BatchFeeInput, VmVersion, U256}; +use zksync_types::{ + fee_model::{BatchFeeInput, L1PeggedBatchFeeModelInput, PubdataIndependentBatchFeeModelInput}, + VmVersion, U256, +}; use crate::vm_latest::L1BatchEnv; @@ -38,7 +41,10 @@ pub fn derive_base_fee_and_gas_per_pubdata( batch_fee_input.into_l1_pegged(), ) } - VmVersion::Vm1_4_1 => crate::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata( + VmVersion::Vm1_4_1 => crate::vm_1_4_1::utils::fee::derive_base_fee_and_gas_per_pubdata( + batch_fee_input.into_pubdata_independent(), + ), + VmVersion::Vm1_4_2 => crate::vm_latest::utils::fee::derive_base_fee_and_gas_per_pubdata( batch_fee_input.into_pubdata_independent(), ), } @@ -62,7 +68,8 @@ pub fn get_batch_base_fee(l1_batch_env: &L1BatchEnv, vm_version: VmVersion) -> u VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::utils::fee::get_batch_base_fee(l1_batch_env) } - VmVersion::Vm1_4_1 => crate::vm_latest::utils::fee::get_batch_base_fee(l1_batch_env), + VmVersion::Vm1_4_1 => crate::vm_1_4_1::utils::fee::get_batch_base_fee(l1_batch_env), + VmVersion::Vm1_4_2 => crate::vm_latest::utils::fee::get_batch_base_fee(l1_batch_env), } } @@ -75,14 +82,37 @@ pub fn adjust_pubdata_price_for_tx( if U256::from(derive_base_fee_and_gas_per_pubdata(batch_fee_input, vm_version).1) <= tx_gas_per_pubdata_limit { + // gas per pubdata is already smaller than or equal to `tx_gas_per_pubdata_limit`. return batch_fee_input; } - // The latest VM supports adjusting the pubdata price for all the types of the fee models. - crate::vm_latest::utils::fee::adjust_pubdata_price_for_tx( - batch_fee_input, - tx_gas_per_pubdata_limit, - ) + match batch_fee_input { + BatchFeeInput::L1Pegged(fee_input) => { + // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` + // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` + let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)) + / U256::from(17); + + BatchFeeInput::L1Pegged(L1PeggedBatchFeeModelInput { + l1_gas_price: new_l1_gas_price.as_u64(), + ..fee_input + }) + } + BatchFeeInput::PubdataIndependent(fee_input) => { + // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` + // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` + // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` + let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) + * (tx_gas_per_pubdata_limit - U256::from(1u32)); + + BatchFeeInput::PubdataIndependent(PubdataIndependentBatchFeeModelInput { + fair_pubdata_price: new_fair_pubdata_price.as_u64(), + ..fee_input + }) + } + } } pub fn derive_overhead( @@ -140,7 +170,8 @@ pub fn derive_overhead( ), ) } - VmVersion::Vm1_4_1 => crate::vm_latest::utils::overhead::derive_overhead(encoded_len), + VmVersion::Vm1_4_1 => crate::vm_1_4_1::utils::overhead::derive_overhead(encoded_len), + VmVersion::Vm1_4_2 => crate::vm_latest::utils::overhead::derive_overhead(encoded_len), } } @@ -162,7 +193,8 @@ pub fn get_bootloader_encoding_space(version: VmVersion) -> u32 { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::BOOTLOADER_TX_ENCODING_SPACE } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::BOOTLOADER_TX_ENCODING_SPACE, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::BOOTLOADER_TX_ENCODING_SPACE, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::BOOTLOADER_TX_ENCODING_SPACE, } } @@ -180,7 +212,8 @@ pub fn get_bootloader_max_txs_in_batch(version: VmVersion) -> usize { crate::vm_refunds_enhancement::constants::MAX_TXS_IN_BLOCK } VmVersion::VmBoojumIntegration => crate::vm_boojum_integration::constants::MAX_TXS_IN_BLOCK, - VmVersion::Vm1_4_1 => crate::vm_latest::constants::MAX_TXS_IN_BATCH, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::MAX_TXS_IN_BATCH, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::MAX_TXS_IN_BATCH, } } @@ -199,7 +232,8 @@ pub fn gas_bootloader_batch_tip_overhead(version: VmVersion) -> u32 { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::BOOTLOADER_BATCH_TIP_OVERHEAD } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_OVERHEAD, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::BOOTLOADER_BATCH_TIP_OVERHEAD, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::BOOTLOADER_BATCH_TIP_OVERHEAD, } } @@ -220,6 +254,7 @@ pub fn get_max_gas_per_pubdata_byte(version: VmVersion) -> u64 { crate::vm_boojum_integration::constants::MAX_GAS_PER_PUBDATA_BYTE } VmVersion::Vm1_4_1 => crate::vm_latest::constants::MAX_GAS_PER_PUBDATA_BYTE, + VmVersion::Vm1_4_2 => crate::vm_1_4_1::constants::MAX_GAS_PER_PUBDATA_BYTE, } } @@ -241,7 +276,8 @@ pub fn get_used_bootloader_memory_bytes(version: VmVersion) -> usize { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::USED_BOOTLOADER_MEMORY_BYTES } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_BYTES, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::USED_BOOTLOADER_MEMORY_BYTES, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_BYTES, } } @@ -263,6 +299,7 @@ pub fn get_used_bootloader_memory_words(version: VmVersion) -> usize { VmVersion::VmBoojumIntegration => { crate::vm_boojum_integration::constants::USED_BOOTLOADER_MEMORY_WORDS } - VmVersion::Vm1_4_1 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_WORDS, + VmVersion::Vm1_4_1 => crate::vm_1_4_1::constants::USED_BOOTLOADER_MEMORY_WORDS, + VmVersion::Vm1_4_2 => crate::vm_latest::constants::USED_BOOTLOADER_MEMORY_WORDS, } } diff --git a/core/lib/multivm/src/versions/mod.rs b/core/lib/multivm/src/versions/mod.rs index 0fc9111aa9a2..a13946c3852c 100644 --- a/core/lib/multivm/src/versions/mod.rs +++ b/core/lib/multivm/src/versions/mod.rs @@ -1,4 +1,5 @@ pub mod vm_1_3_2; +pub mod vm_1_4_1; pub mod vm_boojum_integration; pub mod vm_latest; pub mod vm_m5; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs b/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs index 2682b6183c52..08e4e1c9e49e 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/implementation/snapshots.rs @@ -4,11 +4,7 @@ use vise::{Buckets, EncodeLabelSet, EncodeLabelValue, Family, Histogram, Metrics use zk_evm_1_4_1::aux_structures::Timestamp; use zksync_state::WriteStorage; -use crate::vm_1_4_1::{ - old_vm::{history_recorder::HistoryEnabled, oracles::OracleWithHistory}, - types::internals::VmSnapshot, - vm::Vm, -}; +use crate::vm_1_4_1::{old_vm::oracles::OracleWithHistory, types::internals::VmSnapshot, vm::Vm}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EncodeLabelSet, EncodeLabelValue)] #[metrics(label = "stage", rename_all = "snake_case")] @@ -22,7 +18,7 @@ enum RollbackStage { } #[derive(Debug, Metrics)] -#[metrics(prefix = "server_vm")] +#[metrics(prefix = "server_vm_1_4_1")] struct VmMetrics { #[metrics(buckets = Buckets::LATENCIES)] rollback_time: Family>, @@ -32,7 +28,7 @@ struct VmMetrics { static METRICS: vise::Global = vise::Global::new(); /// Implementation of VM related to rollbacks inside virtual machine -impl Vm { +impl Vm { pub(crate) fn make_snapshot_inner(&mut self) { self.snapshots.push(VmSnapshot { // Vm local state contains O(1) various parameters (registers/etc). diff --git a/core/lib/multivm/src/versions/vm_1_4_1/mod.rs b/core/lib/multivm/src/versions/vm_1_4_1/mod.rs index c3df28f6c31c..83693e4b24e9 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/mod.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/mod.rs @@ -28,8 +28,6 @@ pub mod constants; mod implementation; mod old_vm; mod oracles; -#[cfg(test)] -mod tests; pub(crate) mod tracers; mod types; pub mod utils; diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs index c69daa0927b5..831466be318c 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/pubdata_tracer.rs @@ -57,23 +57,6 @@ impl PubdataTracer { } } - // Creates the pubdata tracer with constant state diffs. - // To be used in tests only. - #[cfg(test)] - pub(crate) fn new_with_forced_state_diffs( - l1_batch_env: L1BatchEnv, - execution_mode: VmExecutionMode, - forced_state_diffs: Vec, - ) -> Self { - Self { - l1_batch_env, - pubdata_info_requested: false, - execution_mode, - enforced_state_diffs: Some(forced_state_diffs), - _phantom_data: Default::default(), - } - } - // Packs part of L1 Messenger total pubdata that corresponds to // `L2toL1Logs` sent in the block fn get_total_user_logs( diff --git a/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs b/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs index 9fba21c42078..6f942a807e78 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/tracers/refunds.rs @@ -212,7 +212,7 @@ impl VmTracer for RefundsTracer { ]); #[derive(Debug, Metrics)] - #[metrics(prefix = "vm")] + #[metrics(prefix = "vm_1_4_1")] struct RefundMetrics { #[metrics(buckets = PERCENT_BUCKETS)] refund: Family>, diff --git a/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs b/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs index beb85468241b..6498a86d3536 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/utils/fee.rs @@ -1,8 +1,5 @@ //! Utility functions for vm -use zksync_types::{ - fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, - U256, -}; +use zksync_types::fee_model::PubdataIndependentBatchFeeModelInput; use zksync_utils::ceil_div; use crate::vm_1_4_1::{constants::MAX_GAS_PER_PUBDATA_BYTE, L1BatchEnv}; @@ -37,34 +34,3 @@ pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_pubdata_independent()); base_fee } - -/// Changes the fee model output so that the expected gas per pubdata is smaller than or the `tx_gas_per_pubdata_limit`. -/// This function expects that the currently expected gas per pubdata is greater than the `tx_gas_per_pubdata_limit`. -pub(crate) fn adjust_pubdata_price_for_tx( - mut batch_fee_input: BatchFeeInput, - tx_gas_per_pubdata_limit: U256, -) -> BatchFeeInput { - match &mut batch_fee_input { - BatchFeeInput::L1Pegged(fee_input) => { - // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` - // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` - let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)) - / U256::from(17); - - fee_input.l1_gas_price = new_l1_gas_price.as_u64(); - } - BatchFeeInput::PubdataIndependent(fee_input) => { - // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` - // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` - let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)); - - fee_input.fair_pubdata_price = new_fair_pubdata_price.as_u64(); - } - } - - batch_fee_input -} diff --git a/core/lib/multivm/src/versions/vm_1_4_1/vm.rs b/core/lib/multivm/src/versions/vm_1_4_1/vm.rs index d87b8d96586c..5684c8821abb 100644 --- a/core/lib/multivm/src/versions/vm_1_4_1/vm.rs +++ b/core/lib/multivm/src/versions/vm_1_4_1/vm.rs @@ -16,7 +16,7 @@ use crate::{ }, vm_1_4_1::{ bootloader_state::BootloaderState, - old_vm::{events::merge_events, history_recorder::HistoryEnabled}, + old_vm::events::merge_events, tracers::dispatcher::TracerDispatcher, types::internals::{new_vm_state, VmSnapshot, ZkSyncVmState}, }, @@ -187,7 +187,7 @@ impl VmInterface for Vm { } /// Methods of vm, which required some history manipulations -impl VmInterfaceHistoryEnabled for Vm { +impl VmInterfaceHistoryEnabled for Vm { /// Create snapshot of current vm state and push it into the memory fn make_snapshot(&mut self) { self.make_snapshot_inner() diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs index 0c836f64097f..d5d61aceafcf 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/execution.rs @@ -20,7 +20,7 @@ use crate::{ impl Vm { pub(crate) fn inspect_inner( &mut self, - dispatcher: TracerDispatcher, + dispatcher: TracerDispatcher, execution_mode: VmExecutionMode, custom_pubdata_tracer: Option>, ) -> VmExecutionResultAndLogs { @@ -44,14 +44,14 @@ impl Vm { /// Collect the result from the default tracers. fn inspect_and_collect_results( &mut self, - dispatcher: TracerDispatcher, + dispatcher: TracerDispatcher, execution_mode: VmExecutionMode, with_refund_tracer: bool, custom_pubdata_tracer: Option>, ) -> (VmExecutionStopReason, VmExecutionResultAndLogs) { let refund_tracers = with_refund_tracer.then_some(RefundsTracer::new(self.batch_env.clone())); - let mut tx_tracer: DefaultExecutionTracer = DefaultExecutionTracer::new( + let mut tx_tracer: DefaultExecutionTracer = DefaultExecutionTracer::new( self.system_env.default_validation_computational_gas_limit, execution_mode, dispatcher, @@ -104,7 +104,7 @@ impl Vm { /// Execute vm with given tracers until the stop reason is reached. fn execute_with_default_tracer( &mut self, - tracer: &mut DefaultExecutionTracer, + tracer: &mut DefaultExecutionTracer, ) -> VmExecutionStopReason { tracer.initialize_tracer(&mut self.state); let result = loop { diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs b/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs index 13932dd3c382..184430568cbc 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/gas.rs @@ -9,7 +9,7 @@ use crate::{ impl Vm { pub(crate) fn calculate_computational_gas_used( &self, - tracer: &DefaultExecutionTracer, + tracer: &DefaultExecutionTracer, gas_remaining_before: u32, spent_pubdata_counter_before: u32, ) -> u32 { diff --git a/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs b/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs index 3e969d951b51..f0984d02dc18 100644 --- a/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs +++ b/core/lib/multivm/src/versions/vm_latest/implementation/statistics.rs @@ -18,7 +18,7 @@ impl Vm { &self, timestamp_initial: Timestamp, cycles_initial: u32, - tracer: &DefaultExecutionTracer, + tracer: &DefaultExecutionTracer, gas_remaining_before: u32, gas_remaining_after: u32, spent_pubdata_counter_before: u32, diff --git a/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs b/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs index dbe0afa33fa1..829aa93b13da 100644 --- a/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs +++ b/core/lib/multivm/src/versions/vm_latest/tests/tester/inner_state.rs @@ -79,7 +79,7 @@ pub(crate) struct VmInstanceInnerState { impl Vm { // Dump inner state of the VM. - pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { + pub(crate) fn dump_inner_state(&self) -> VmInstanceInnerState { let event_sink = self.state.event_sink.clone(); let precompile_processor_state = PrecompileProcessorTestInnerState { timestamp_history: self.state.precompiles_processor.timestamp_history.clone(), diff --git a/core/lib/multivm/src/versions/vm_latest/utils/fee.rs b/core/lib/multivm/src/versions/vm_latest/utils/fee.rs index ea4de7204434..c17e585330c9 100644 --- a/core/lib/multivm/src/versions/vm_latest/utils/fee.rs +++ b/core/lib/multivm/src/versions/vm_latest/utils/fee.rs @@ -1,8 +1,5 @@ //! Utility functions for vm -use zksync_types::{ - fee_model::{BatchFeeInput, PubdataIndependentBatchFeeModelInput}, - U256, -}; +use zksync_types::fee_model::PubdataIndependentBatchFeeModelInput; use zksync_utils::ceil_div; use crate::vm_latest::{constants::MAX_GAS_PER_PUBDATA_BYTE, L1BatchEnv}; @@ -37,34 +34,3 @@ pub(crate) fn get_batch_base_fee(l1_batch_env: &L1BatchEnv) -> u64 { derive_base_fee_and_gas_per_pubdata(l1_batch_env.fee_input.into_pubdata_independent()); base_fee } - -/// Changes the fee model output so that the expected gas per pubdata is smaller than or the `tx_gas_per_pubdata_limit`. -/// This function expects that the currently expected gas per pubdata is greater than the `tx_gas_per_pubdata_limit`. -pub(crate) fn adjust_pubdata_price_for_tx( - mut batch_fee_input: BatchFeeInput, - tx_gas_per_pubdata_limit: U256, -) -> BatchFeeInput { - match &mut batch_fee_input { - BatchFeeInput::L1Pegged(fee_input) => { - // `gasPerPubdata = ceil(17 * l1gasprice / fair_l2_gas_price)` - // `gasPerPubdata <= 17 * l1gasprice / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) / 17 <= l1gasprice` - let new_l1_gas_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)) - / U256::from(17); - - fee_input.l1_gas_price = new_l1_gas_price.as_u64(); - } - BatchFeeInput::PubdataIndependent(fee_input) => { - // `gasPerPubdata = ceil(fair_pubdata_price / fair_l2_gas_price)` - // `gasPerPubdata <= fair_pubdata_price / fair_l2_gas_price + 1` - // `fair_l2_gas_price(gasPerPubdata - 1) <= fair_pubdata_price` - let new_fair_pubdata_price = U256::from(fee_input.fair_l2_gas_price) - * (tx_gas_per_pubdata_limit - U256::from(1u32)); - - fee_input.fair_pubdata_price = new_fair_pubdata_price.as_u64(); - } - } - - batch_fee_input -} diff --git a/core/lib/multivm/src/versions/vm_latest/vm.rs b/core/lib/multivm/src/versions/vm_latest/vm.rs index f570bdac72ee..a2257f96b5c3 100644 --- a/core/lib/multivm/src/versions/vm_latest/vm.rs +++ b/core/lib/multivm/src/versions/vm_latest/vm.rs @@ -29,7 +29,7 @@ use crate::{ pub struct Vm { pub(crate) bootloader_state: BootloaderState, // Current state and oracles of virtual machine - pub(crate) state: ZkSyncVmState, + pub(crate) state: ZkSyncVmState, pub(crate) storage: StoragePtr, pub(crate) system_env: SystemEnv, pub(crate) batch_env: L1BatchEnv, @@ -39,7 +39,7 @@ pub struct Vm { } impl VmInterface for Vm { - type TracerDispatcher = TracerDispatcher; + type TracerDispatcher = TracerDispatcher; fn new(batch_env: L1BatchEnv, system_env: SystemEnv, storage: StoragePtr) -> Self { let (state, bootloader_state) = new_vm_state(storage.clone(), &system_env, &batch_env); diff --git a/core/lib/multivm/src/vm_instance.rs b/core/lib/multivm/src/vm_instance.rs index a742a65f73a4..cbea46649284 100644 --- a/core/lib/multivm/src/vm_instance.rs +++ b/core/lib/multivm/src/vm_instance.rs @@ -20,7 +20,8 @@ pub enum VmInstance { VmVirtualBlocks(crate::vm_virtual_blocks::Vm), VmVirtualBlocksRefundsEnhancement(crate::vm_refunds_enhancement::Vm), VmBoojumIntegration(crate::vm_boojum_integration::Vm), - Vm1_4_1(crate::vm_latest::Vm), + Vm1_4_1(crate::vm_1_4_1::Vm), + Vm1_4_2(crate::vm_latest::Vm), } macro_rules! dispatch_vm { @@ -33,6 +34,7 @@ macro_rules! dispatch_vm { VmInstance::VmVirtualBlocksRefundsEnhancement(vm) => vm.$function($($params)*), VmInstance::VmBoojumIntegration(vm) => vm.$function($($params)*), VmInstance::Vm1_4_1(vm) => vm.$function($($params)*), + VmInstance::Vm1_4_2(vm) => vm.$function($($params)*), } }; } @@ -205,9 +207,13 @@ impl VmInstance { VmInstance::VmBoojumIntegration(vm) } VmVersion::Vm1_4_1 => { - let vm = crate::vm_latest::Vm::new(l1_batch_env, system_env, storage_view); + let vm = crate::vm_1_4_1::Vm::new(l1_batch_env, system_env, storage_view); VmInstance::Vm1_4_1(vm) } + VmVersion::Vm1_4_2 => { + let vm = crate::vm_latest::Vm::new(l1_batch_env, system_env, storage_view); + VmInstance::Vm1_4_2(vm) + } } } } diff --git a/core/lib/types/src/protocol_version.rs b/core/lib/types/src/protocol_version.rs index 639ff7f6192b..5d8b982aef53 100644 --- a/core/lib/types/src/protocol_version.rs +++ b/core/lib/types/src/protocol_version.rs @@ -42,6 +42,7 @@ pub enum ProtocolVersionId { Version19, Version20, Version21, + Version22, } impl ProtocolVersionId { @@ -78,7 +79,8 @@ impl ProtocolVersionId { ProtocolVersionId::Version18 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version19 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version20 => VmVersion::Vm1_4_1, - ProtocolVersionId::Version21 => VmVersion::Vm1_4_1, + ProtocolVersionId::Version21 => VmVersion::Vm1_4_2, + ProtocolVersionId::Version22 => VmVersion::Vm1_4_2, } } @@ -764,7 +766,8 @@ impl From for VmVersion { ProtocolVersionId::Version18 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version19 => VmVersion::VmBoojumIntegration, ProtocolVersionId::Version20 => VmVersion::Vm1_4_1, - ProtocolVersionId::Version21 => VmVersion::Vm1_4_1, + ProtocolVersionId::Version21 => VmVersion::Vm1_4_2, + ProtocolVersionId::Version22 => VmVersion::Vm1_4_2, } } } diff --git a/core/lib/types/src/vm_version.rs b/core/lib/types/src/vm_version.rs index 2a4e9dc3ef2e..5fa6c76b933f 100644 --- a/core/lib/types/src/vm_version.rs +++ b/core/lib/types/src/vm_version.rs @@ -9,11 +9,12 @@ pub enum VmVersion { VmVirtualBlocksRefundsEnhancement, VmBoojumIntegration, Vm1_4_1, + Vm1_4_2, } impl VmVersion { /// Returns the latest supported VM version. pub const fn latest() -> VmVersion { - Self::Vm1_4_1 + Self::Vm1_4_2 } } diff --git a/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs b/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs index e6add9a9e3b1..58d573796316 100644 --- a/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs +++ b/core/lib/zksync_core/src/api_server/execution_sandbox/tracers.rs @@ -14,7 +14,7 @@ pub(crate) enum ApiTracer { impl ApiTracer { pub fn into_boxed< S: WriteStorage, - H: HistoryMode + multivm::HistoryMode + 'static, + H: HistoryMode + multivm::HistoryMode + 'static, >( self, ) -> MultiVmTracerPointer { diff --git a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs index ba1463038277..cceea1fa16e2 100644 --- a/core/lib/zksync_core/src/api_server/tx_sender/mod.rs +++ b/core/lib/zksync_core/src/api_server/tx_sender/mod.rs @@ -63,6 +63,8 @@ pub struct MultiVMBaseSystemContracts { pub(crate) post_allowlist_removal: BaseSystemContracts, /// Contracts to be used after the 1.4.1 upgrade pub(crate) post_1_4_1: BaseSystemContracts, + /// Contracts to be used after the 1.4.2 upgrade + pub(crate) post_1_4_2: BaseSystemContracts, } impl MultiVMBaseSystemContracts { @@ -88,7 +90,8 @@ impl MultiVMBaseSystemContracts { | ProtocolVersionId::Version17 => self.post_virtual_blocks_finish_upgrade_fix, ProtocolVersionId::Version18 => self.post_boojum, ProtocolVersionId::Version19 => self.post_allowlist_removal, - ProtocolVersionId::Version20 | ProtocolVersionId::Version21 => self.post_1_4_1, + ProtocolVersionId::Version20 => self.post_1_4_1, + ProtocolVersionId::Version21 | ProtocolVersionId::Version22 => self.post_1_4_2, } } } @@ -121,6 +124,7 @@ impl ApiContracts { post_boojum: BaseSystemContracts::estimate_gas_post_boojum(), post_allowlist_removal: BaseSystemContracts::estimate_gas_post_allowlist_removal(), post_1_4_1: BaseSystemContracts::estimate_gas_post_1_4_1(), + post_1_4_2: BaseSystemContracts::estimate_gas_post_1_4_2(), }, eth_call: MultiVMBaseSystemContracts { pre_virtual_blocks: BaseSystemContracts::playground_pre_virtual_blocks(), @@ -130,6 +134,7 @@ impl ApiContracts { post_boojum: BaseSystemContracts::playground_post_boojum(), post_allowlist_removal: BaseSystemContracts::playground_post_allowlist_removal(), post_1_4_1: BaseSystemContracts::playground_post_1_4_1(), + post_1_4_2: BaseSystemContracts::playground_post_1_4_2(), }, } } diff --git a/core/tests/ts-integration/tests/api/web3.test.ts b/core/tests/ts-integration/tests/api/web3.test.ts index 185c9d3dd079..8cdde989a9e3 100644 --- a/core/tests/ts-integration/tests/api/web3.test.ts +++ b/core/tests/ts-integration/tests/api/web3.test.ts @@ -729,12 +729,24 @@ describe('web3 API compatibility tests', () => { let latestBlock = await alice.provider.getBlock('latest'); // Check API returns identical logs by block number and block hash. - const getLogsByNumber = await alice.provider.getLogs({ - fromBlock: latestBlock.number, - toBlock: latestBlock.number + // Logs can have different `l1BatchNumber` field though, + // if L1 batch was sealed in between API requests are processed. + const getLogsByNumber = ( + await alice.provider.getLogs({ + fromBlock: latestBlock.number, + toBlock: latestBlock.number + }) + ).map((x) => { + x.l1BatchNumber = 0; // Set bogus value. + return x; }); - const getLogsByHash = await alice.provider.getLogs({ - blockHash: latestBlock.hash + const getLogsByHash = ( + await alice.provider.getLogs({ + blockHash: latestBlock.hash + }) + ).map((x) => { + x.l1BatchNumber = 0; // Set bogus value. + return x; }); await expect(getLogsByNumber).toEqual(getLogsByHash); diff --git a/etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin b/etc/multivm_bootloaders/vm_1_4_2/fee_estimate.yul/fee_estimate.yul.zbin new file mode 100644 index 0000000000000000000000000000000000000000..a020cd118c7a8081b0a5c127e0b906093b9718e1 GIT binary patch literal 65888 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

    p7C3`2p#>sJ~b+ z{$k>S8v0J|*%yDZmfoZO&rR=GCRZs`z^e>DR38*Yd;`iN_`RyAfS4H~fitG4p3S$MUH%Tcw}!{f0Ef z$#^`f#PN-Q4|#lDTa90o;{8uu*Hq`rw1VCc{3JP!rcx{AyAi3C@_h*Q!y&fN6F1X1 zok5*GDCO`yYs@$CC--t!pC@*5g#HZ3?{hPsfMc!orT!jVH+=0p>jnKiIDFPa>v#TM zT=%O?zI;Ef>rTO^eP5p3ey)zX-^J$A!U9S@89}Jc|bZYP6S!K5A6| zZT#HaVE8tE^u0Wb)_;AklYyT(p2)HN{c`pFoLx^DeKv1<%lkRIzHj7D_H%as*yytp zv!9dNBffSY)pR^+_#AN##D9Sg{tl#DV}EORPh;@W-Dcrq<#U4%j`LI>f0pf=lN9@& zPGxD`sr#IYco-HtC+k7V$rNN?t~w}o&e**S^F{Y>X*~GfQ`G!%p^cB^28Nr|{w(Ze z_5Hrdq^w67dzV}x_AaqP>|Nq=ZSPi6zbf9}SCDu>#eKg2D*kKteEDfdMLZVk!sAsI zKbiCW{`%eG?w2<51*uw?-LUoUw`%C!%WV8Nxcx_Jw10Yi^Ox>>7EEv6zuEm3BR47W zXZ1e$6Fq-1{!hL4E_8oX^e_Au(YyZV*Dbwpg6*#RCc(?x&QTy9`ZdhO zI^ZA6^Ox5CAUO5-!y+vHmGy#LWF3L>Ioib4Q`LXLZp?oVot4L2_p5Q)) z_7U6f*&uk%JfrzQ^PMTD_aVT}nEdMNEB^kZ1co})dx^ikLIC?Q%EJ8ii}WDQSY-bm z^Id{d;k$;&xk>D`#2YZu3u)fnbE@Gd*)P(wPQyFV`$Zh+joZP3`rxSfQmgw{d@h@NjUh)e3Oa24m9QJnydxoXo?%l)> zy%$&HQ|jNUP<}k02K8+|B|L=jl7Jsi^IOl6_(Lwi@sDN?_Y^ZLw+OprWZR&juL#Y zI(+wZ#D5^)y@=OePx$fusX4ZDisny^_XOg#f|mx52Yxh@496at`>k-lg|LXuhKTP#iA-JrNJ=`FE`k65tO?--x&r z=!<;}%rA&fua@<=WNL=m$?0<@Bcf+Q>vfV}@Yn0kmiTqjtk+5YYoO^%v?`UgdrlVtB|57F`@0klVEVpN%Ddn9=_31P4P9w< zO8AfcGT?cT?7#cp4%_LzmuSBS?kxLX%TwYH9MyO@U-LEauGi1DI`DV(Ir>&Iu-mj?H`^cal7OOht_30e9Z~81!HNy zFnJcW+xuDRSKm&N50umOQ+aB?5BsRDXMO-5Q$KvUO!7KW-~F22F8WD)UqC+?KZqx? z|Cw09`1wJS*E0z}gA6ah`+57|D<0+dqzf)CjT4KdVoL_Xl+ozD;Se&52&pn-$&XuRlg zh(G8h#6Q>j2Mu1_A2`u*8$LSE=r=fogjbbdJ<*4;V;rP)L=RB<#pDl)A7}hRj6?jn zocMFd=XL-`(hFuEgWmTFbwhfttlVt0+zk0YLw%oGs2=I-()63B9_d@6>8bTd-=K!~ zTt6@?y;q|O$tnBG%&#=gf1v9icpt0bYhp~Ym%zh<{7d_usV52Vkn;z1 zKNbq#_HXoebQ%Vq&V!I1H2$Cdj!whi+x^$y88Yzaz0PglU-i8x-scV1KBxOc6z+og z#rB7P++g_6x9Iu92E(`M`JqLIf4{(w_vayJUl2KqKKnjn{CPhe{)4l=@AJ|0zK5;% zFPL{y45=5g{|i%vw^>+g_7~U=!--(Om~!Ic)#Nuzy!t8X|I!~<)Q>2p`a}7#`Z1Jm z=|}f}YQQIcTNSEbFZ`d>fKU9e5cof>0e_+Wx6T(Uh6m~_C?34@$+^aZm!7KaF~@_K zK2ebmWSl{MJe`7kiw}t1!t+D-XEpG;P`W)p@PS7ihfxgg1mbmz#w(v&u7Xz?XMneb z;`Qe>@VY>GR+#3|{KSF341I$a{C_f`S;rTs0Q~x;2gT2H$Dx9R4)R@aJ^u%P%RaZ2 zb?#@IkoejRe}{JIQ*-8X^yetgkD`2N#zS#h(VsjH(x0Lqf5G?+=wthL3#Fg$2XebU zKHXo|XqW4S_^JlqU^*l7N-vS4ak?ECqR@r+UE;hdrw4Szc?6nI(JU~qD@q;1JO}eT z_g6_hPXZh&hk12@;F@!TPI7e-KBoIjN|!_XTrMT$o=r$P)*knA~c z0-kJm3$%;A9V7uIeey#izcT*@8fj-X{b8PjesjDOeuO-q)X%3Ze+fjxUxMi)bjU^c zoAN20=p=eAsu#dylHNq}m+ybNBE1Not3vs)^a|zM_{OlS!pFRIA@G$xH|IX)upIUm z&>Zw****fTr{}kSp#Pah?H}kzOt{GUTgzRY@zj3IrD=Q^VVd}<{{ju~If{eyUu5{% zvPWPqiT8oQ&`(1rqR&zEzieG>zVzYsFwp0bh~9#JjOZ(HyTf{_A3BWNXFsw3SBCHX z{yl`E@%^joz6%qFpQ*QhI{s?b7oe3q(%0Azz)y%Z#U~*&*1QO>s=xnPKmI~-PKv)K zP@kSB+Ww^*Z2yeCv+W?x6R@4bH38z!C0Db3!vP23zqI)4vuQc!r5v0~1wJa-MH8RQ zkUa!nMeQLf!hrSTLHz+QspToYzZZ5fdS6L8E%^>su5Jfua89>Ka!Yg}`p-!TYq)4~ZPZN$c}& z*odL=bE?F_)2Hh5Ec!kg_;Kf=y9)4cruNIuy9ge!Wsv({aM&Li_#W&S_EN~coREC! z@wjcEQ=Z`Ib25aG{-B&2Z(n>lt+if9@=fwf;z8px`_hphe!Ic*V{^oF+5T$_-#E9Q zm-YnTKhbd03Bzx4zABj#{1ZR0pP1I`3^+&4>k#Qp(Q`(roW^_J&_%CT7`*d3RDJsc zVW-)z0AI`VS-W6Qg#yjs~R`AWT)(>F@_X0O%k_mcAW>GYhR{t_;KL(0@Yi{D3*=KX{8 zp7xU5KWHiT|Cha4^OKj7et)W&%coU~Zkm#icC zUxweppUF2%x#a6P{fO8>=UCDcI7VM0pY)s7pV((+^yw7g)$A`@_FjK~nXYfv5mPrv z{j&XK)3RS`Zu`EL{hjoWyXZ#LznWKJcyRz(Y=|A#iJytn< zz7hp=c}JJW{10|$*;Bea`TaazJ#S25-y7zi%Pxyho(Mg_%;$Mg7vGm@M^(4}B zG=9Av(?si4d5jYxU z-^P#LXVozHHh%OztA@e1`+w8o@=p`Z@4=rH)_o{`K&l7I2mjN4EQkl5xD}D=4SdPB z<96JH^-m~2)=voK+kOD~$*ZVQ#}hr}$7Okc4Z0!z(;)UiKyM9PC;GpsS^P^_P1!F+ z`)K!|*9y;mJP`LPfWMn(bbb!$^nOI%-Q!6)ucu@`%fRckzDy^x;)mm0J;CveJxH%4 zdpdv^Tb}hsMx}a?pUM>2AMx<~9Nv{K2YY-k$~Dg-1cP?r{>wfwoSPTBow7y?P+j_3<~Ot-Z-V)T_y=Ge&v^^@r!C4qGz|c~X@7Kl9FFYOst~`_%}=Ng zJ{XYrIklsLeH8=$T#=8_ZgNK`Kfc|deigZEWK9>5=XqfqS{JeDW){j|v(of97TxS==n1^pJsEs2#=t`w{t3FTCGaZ~?6+gw+JAI-ek|vNArCzN8~Cz*ex-aKi1~dl@Im|Q z2ru|y_}_njA@KJNHJBQtT+(0Ra(EBb8~9I@TT#0lZmMsidIOK6Jj-PbxZlMH*P^_R ziv;JOxi9nh=Q#de`mIN=sk7?JNO=NM>D z)HU9&;^^MeNRS=(s}xRzOm)0J_2G>_dVK8dPkrp>Z@%+;?|bvu`S-r#mekmnr%ONl z(br$}#B0Ol=kS}x@0oIYO2fm&J!{WC$2%~wd$KrE;x3xpD$nE}zUID9&!Bsi{+gFw zI(fuN{PL>9l}c1dzagA{AtTJ29`~k7)81I=I&Wujdia`kUbs+&-_Gc^BNehZ8Tqp{ z@{eVz6+qsqA5Z>OjUsk-g#5wy#t)VzCr3emxexG^^JZ+|k@r*1EBxb^FLZAF*^2Yt z_?kcXz&AdVoc)ga@V3vt?zD4X^~--tUHyjp5F@PexAwe3m0YFP)@c8ZhmTaPfA3qW z<~yU?)%2k)(@_2u|4N5S!w04#A`>Y)d|-02G&a5I&_ro?x-_!=&}F-Jfs_0)(}y+| zr;ApipR3gNL*57qc;j5n8=dk-$A-rNb68+(!rRE`*lt}QRI}`761k3wWEnTF^>*$ZAKnu-j+syV^EuUl zl;z$RP6_OjvA@w)#BmJQi2gnRsopXqx4SsC1tlcMB!)ns z?)3QZ_+H;VnLY#}PJ6pXC#Oh@T$JB-(T>Y5yl~s5?V(!1&yD%*`5l`#UHanf7X^u- zU+`Jy|JVGbW7R6BK6QV!Y`DWeIyO2U=)$3^$MN8!az8S=xVKbh0#Z z8N7#UO2vq8LGZ>QyhSK>lYim(jYTb2h zwc1L7{uh*XjZc=gOqNIo*}ZbBHgNp-uIs8BpuKCnYv6cS>_mQIqBO<^9E=4o({Q(` zka>LTtIY4X=VS>sb&OQwM692(G_F!84dcIJ3gjEBF#d`0>h=ruLDEg^1;r6`7|JWZ zb2QXq^e5_{PLsDvf5_iHt_3)*OjYtc@xW|c9Y3w(f}Hqo=sDTX1AC{}c~b|5hf7mN zCzt0(@w{)0Lz+HF`^RKy*MYH-(=m+rQRa?z)KXzK$c^EI!&B95!=8!i^b5m^!)0H% zz}$X2;bPms-QGUnv$(s&{7sRS(BGBrou3W8mi-Lte?Z#2=B0pD8ruz*VDs9|=t{&9zwfn=} zDfPER2M`RdgSG|};Xn45cuJP}wz*R5HqlEp}?XM~T#i>KF z^-SW}ldo8J|F7=;*n#8y`@j8UF|}mq{ky-}cgDXg-Ez~@S8V(94}-sK7E77B^fdfH zb}z0a{{Exy{92sMBJF8YJR*!HagI;Gd3LIJu(bUU#g0l- z#OcP`z}-JcJ+9EcBtP-MgIoy1%3pACY^$SFJn+~&N(6q$J^_942-5ILf$tg}8$~yx zE=ZuiW3$z}xBhh;S^WNl_0P07edw~u(cPmVzvbFJ)dg_Z$SxmN+>fjN^m3n8arr^} zqGjwd@u@*6$-j8)#n4WeJCW;pV03KyOawytFPvYly|6Vb02TYIJvKE+YzuzI{#yN= zhaZT|sGJy)uK+*fX?WWXV~W4e+b}*hT{=YGDlK%)`|sY{3*9v;r)%V2F}7!H{JJr4 zjyHXHqFlN+=eKR&apC2gHtpE9`LgXbfLYmyAI?;WFZnups(N@r6{o7IM^&t0zb0xJ zAV0q1PlTg`@bmW-4`E_9J~=vl_`*^Nb24x&iiY#U=?03Q4@D77*TgQ{abIm?7^d#cJBDxw)5S>+umpxK($dE}{xus(uwEj{(#oUPvH$#r7nAHKO-z=~&`k$S>*rSg z;r+(LkJAQ>YJXIwTK@J!UNCZRczoZ)-cr~}+FPt{f2+a%v)h*auv&idmX&|sT&)1| zs7$pYz11?2*HI(CDsgMn{nk@UzrDYPf9uwOfjv1@|Mbis>IIxWUDcH;hf~8j{pQ_0 zH%H*Z{j`B>9`1g^P7A+lHx-_%mfvt@jo&|c?9LZgEwXl9b>q2qU10+_7LkQ1a!|=b zksx-kghL!n`QwwET{g+2wFj*5$m(r$>4&>^X#aIp9Zb_^$j*&>J4gK(dkDX4;^9*gCOGlb#(j)YV;eVpfI={536+EZM ztK};7yO(Tx`K23nY{+llaM6xSH{~zK&&`{I`q#gzuc~|@Ix&6O#5xaAF>i1^W`$!V zOmsK;Yns=NR*!EC@2M_Aa9G6tg%?_a?p6Kuo!*1bFZ!GwU$jPi_nG)w&964;;ci)> zLoU*33RZX)YcMB8eD)Q`4nr~U`Y10nRe%+jd_(7pc71nZq;1b#j~~426(4`<*{}S| WPi}bCk@tM;$It)4#i!hN>;DH3AJ~!r literal 0 HcmV?d00001 diff --git a/etc/multivm_bootloaders/vm_1_4_2/proved_batch.yul/proved_batch.yul.zbin b/etc/multivm_bootloaders/vm_1_4_2/proved_batch.yul/proved_batch.yul.zbin new file mode 100644 index 0000000000000000000000000000000000000000..1ad3bd50502a9e0f9eea7ec2564dc1c2ea9531a9 GIT binary patch literal 64928 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 Date: Fri, 23 Feb 2024 12:52:27 +0100 Subject: [PATCH 049/106] Apdapt protobuf_config --- core/lib/protobuf_config/src/chain.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/lib/protobuf_config/src/chain.rs b/core/lib/protobuf_config/src/chain.rs index dbf50b039bde..c59f7fa86cd4 100644 --- a/core/lib/protobuf_config/src/chain.rs +++ b/core/lib/protobuf_config/src/chain.rs @@ -158,11 +158,13 @@ impl ProtoRepr for proto::StateKeeper { .map(|x| x.try_into()) .transpose() .context("enum_index_migration_chunk_size")?, - l1_batch_commit_data_generator_mode: required(&self.fee_model_version) - // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. - .map(|_x| proto::L1BatchCommitDataGeneratorMode::Rollup) - .context("l1_batch_commit_data_generator_mode")? - .parse(), + l1_batch_commit_data_generator_mode: required( + &self.l1_batch_commit_data_generator_mode, + ) + // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. + .and_then(|x| Ok(proto::L1BatchCommitDataGeneratorMode::try_from(*x)?)) + .context("l1_batch_commit_data_generator_mode")? + .parse(), }) } @@ -202,7 +204,7 @@ impl ProtoRepr for proto::StateKeeper { // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. l1_batch_commit_data_generator_mode: Some( proto::L1BatchCommitDataGeneratorMode::new( - &configs::chain::L1BatchCommitDataGeneratorMode::Rollup, + &this.l1_batch_commit_data_generator_mode, ) .into(), ), From 85954ad3c02ebac2f2e47db60bcc5513c0b19bd6 Mon Sep 17 00:00:00 2001 From: Jordi Date: Fri, 23 Feb 2024 12:52:47 +0100 Subject: [PATCH 050/106] Apdapt testonly --- core/lib/config/src/testonly.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index b11fcd3f563f..823c5fc1486a 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -287,8 +287,7 @@ impl RandomConfig for configs::chain::StateKeeperConfig { upload_witness_inputs_to_gcs: g.gen(), enum_index_migration_chunk_size: g.gen(), // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. - l1_batch_commit_data_generator_mode: - configs::chain::L1BatchCommitDataGeneratorMode::Rollup, + l1_batch_commit_data_generator_mode: g.gen(), } } } @@ -499,7 +498,7 @@ impl RandomConfig for configs::eth_sender::GasAdjusterConfig { poll_period: g.gen(), max_l1_gas_price: g.gen(), // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. - l1_gas_per_pubdata_byte: 17, + l1_gas_per_pubdata_byte: g.gen(), } } } From e11df5e3351834f199531b3d14c0d83b1c40dd4d Mon Sep 17 00:00:00 2001 From: Daniel Lumi <149794418+zk-Lumi@users.noreply.github.com> Date: Fri, 23 Feb 2024 06:25:51 -0700 Subject: [PATCH 051/106] chore: slightly change instructions in node version to match yarn (#1221) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * nit: there was a mismatch in instructions of setting node version vs yarn version ## Why ❔ * make more clear ## Checklist - [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [ ] Tests for the changes have been added / updated. - [ ] Documentation comments have been added / updated. - [ ] Code has been formatted via `zk fmt` and `zk lint`. - [ ] Spellcheck has been run via `zk spellcheck`. - [ ] Linkcheck has been run via `zk linkcheck`. --- docs/guides/setup-dev.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/setup-dev.md b/docs/guides/setup-dev.md index a833fa10f455..c71eebc5a64f 100644 --- a/docs/guides/setup-dev.md +++ b/docs/guides/setup-dev.md @@ -88,7 +88,7 @@ If logging out does not resolve the issue, restarting the computer should. 1. Install `Node` (requires version `v18.18.0`). Since our team attempts to always use the latest LTS version of `Node.js`, we suggest you to install [nvm](https://github.com/nvm-sh/nvm). It will allow you to update `Node.js` - version easily in the future (by running `nvm use` in the root of the repository) + version easily in the future (by running `nvm use v18.18.0` in the root of the repository) 2. Install `yarn` (make sure to get version 1.22.19 - you can change the version by running `yarn set version 1.22.19`). Instructions can be found on the [official site](https://classic.yarnpkg.com/en/docs/install/). Check if `yarn` is installed by running `yarn -v`. If you face any problems when installing `yarn`, it might be the case that your From ce6247effa87286e1fe13249d861f3011a10f3b5 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Fri, 23 Feb 2024 16:24:23 +0100 Subject: [PATCH 052/106] add support for validium in external mode --- core/bin/external_node/src/config/mod.rs | 12 +++++++++++- core/bin/external_node/src/main.rs | 8 ++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index e37a71d79c6f..ed0ea50cdc04 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -4,7 +4,6 @@ use anyhow::Context; use serde::Deserialize; use url::Url; use zksync_basic_types::{Address, L1ChainId, L2ChainId}; -use zksync_config::ObjectStoreConfig; use zksync_consensus_roles::node; use zksync_core::{ api_server::{ @@ -20,6 +19,8 @@ use zksync_web3_decl::{ namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; +use zksync_config::{configs::chain::L1BatchCommitDataGeneratorMode, ObjectStoreConfig}; + #[cfg(test)] mod tests; @@ -200,6 +201,9 @@ pub struct OptionalENConfig { /// 0 means that sealing is synchronous; this is mostly useful for performance comparison, testing etc. #[serde(default = "OptionalENConfig::default_miniblock_seal_queue_capacity")] pub miniblock_seal_queue_capacity: usize, + + #[serde(default = "OptionalENConfig::default_l1_batch_commit_data_generator_mode")] + pub l1_batch_commit_data_generator_mode: L1BatchCommitDataGeneratorMode, } impl OptionalENConfig { @@ -306,6 +310,10 @@ impl OptionalENConfig { 10 } + const fn default_l1_batch_commit_data_generator_mode() -> L1BatchCommitDataGeneratorMode { + L1BatchCommitDataGeneratorMode::Rollup + } + pub fn polling_interval(&self) -> Duration { Duration::from_millis(self.polling_interval) } @@ -384,6 +392,8 @@ pub struct RequiredENConfig { pub state_cache_path: String, /// Fast SSD path. Used as a RocksDB dir for the Merkle tree (*new* implementation). pub merkle_tree_path: String, + /// External node mode. Same as in the main node. + pub l1_batch_commit_data_generator_mode: L1BatchCommitDataGeneratorMode, } impl RequiredENConfig { diff --git a/core/bin/external_node/src/main.rs b/core/bin/external_node/src/main.rs index a2a96dfc6883..85fa1c9a0eac 100644 --- a/core/bin/external_node/src/main.rs +++ b/core/bin/external_node/src/main.rs @@ -8,7 +8,7 @@ use prometheus_exporter::PrometheusExporterConfig; use tokio::{sync::watch, task, time::sleep}; use zksync_basic_types::{Address, L2ChainId}; use zksync_concurrency::{ctx, scope}; -use zksync_config::configs::database::MerkleTreeMode; +use zksync_config::configs::{chain::L1BatchCommitDataGeneratorMode, database::MerkleTreeMode}; use zksync_core::{ api_server::{ execution_sandbox::VmConcurrencyLimiter, @@ -37,7 +37,10 @@ use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; use zksync_health_check::{CheckHealth, HealthStatus, ReactiveHealthCheck}; use zksync_state::PostgresStorageCaches; use zksync_storage::RocksDB; -use zksync_types::l1_batch_commit_data_generator::RollupModeL1BatchCommitDataGenerator; +use zksync_types::l1_batch_commit_data_generator::{ + L1BatchCommitDataGenerator, RollupModeL1BatchCommitDataGenerator, + ValidiumModeL1BatchCommitDataGenerator, +}; use zksync_utils::wait_for_tasks::wait_for_tasks; use crate::{ @@ -241,6 +244,7 @@ async fn init_tasks( healthchecks.push(Box::new(metadata_calculator.tree_health_check())); let l1_batch_commit_data_generator: Arc = match config + .optional .l1_batch_commit_data_generator_mode { L1BatchCommitDataGeneratorMode::Rollup => Arc::new(RollupModeL1BatchCommitDataGenerator {}), From 57f4bbef96db387ebd438cb5ccafe4fae78df898 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Fri, 23 Feb 2024 16:37:18 +0100 Subject: [PATCH 053/106] update tests --- core/bin/external_node/src/config/mod.rs | 3 +-- core/bin/external_node/src/config/tests.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index ed0ea50cdc04..46b97550483b 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -4,6 +4,7 @@ use anyhow::Context; use serde::Deserialize; use url::Url; use zksync_basic_types::{Address, L1ChainId, L2ChainId}; +use zksync_config::{configs::chain::L1BatchCommitDataGeneratorMode, ObjectStoreConfig}; use zksync_consensus_roles::node; use zksync_core::{ api_server::{ @@ -19,8 +20,6 @@ use zksync_web3_decl::{ namespaces::{EthNamespaceClient, ZksNamespaceClient}, }; -use zksync_config::{configs::chain::L1BatchCommitDataGeneratorMode, ObjectStoreConfig}; - #[cfg(test)] mod tests; diff --git a/core/bin/external_node/src/config/tests.rs b/core/bin/external_node/src/config/tests.rs index 243be39a1139..8eb9792b8eee 100644 --- a/core/bin/external_node/src/config/tests.rs +++ b/core/bin/external_node/src/config/tests.rs @@ -25,6 +25,10 @@ fn parsing_optional_config_from_empty_env() { 128 * BYTES_IN_MEGABYTE ); assert_eq!(config.max_response_body_size(), 10 * BYTES_IN_MEGABYTE); + assert_eq!( + config.l1_batch_commit_data_generator_mode, + L1BatchCommitDataGeneratorMode::Rollup + ); } #[test] @@ -44,6 +48,7 @@ fn parsing_optional_config_from_env() { ("EN_MERKLE_TREE_MULTI_GET_CHUNK_SIZE", "1000"), ("EN_MERKLE_TREE_BLOCK_CACHE_SIZE_MB", "32"), ("EN_MAX_RESPONSE_BODY_SIZE_MB", "1"), + ("EN_L1_BATCH_COMMIT_DATA_GENERATOR_MODE", "Validium"), ]; let env_vars = env_vars .into_iter() @@ -70,4 +75,8 @@ fn parsing_optional_config_from_env() { 32 * BYTES_IN_MEGABYTE ); assert_eq!(config.max_response_body_size(), BYTES_IN_MEGABYTE); + assert_eq!( + config.l1_batch_commit_data_generator_mode, + L1BatchCommitDataGeneratorMode::Validium + ); } From 6cd69aa33013ce8d69f01a2fd002c392e4710ce3 Mon Sep 17 00:00:00 2001 From: Marcin M <128217157+mm-zk@users.noreply.github.com> Date: Fri, 23 Feb 2024 17:10:04 +0100 Subject: [PATCH 054/106] fix(zk): Adapting zk status prover to new Database layout (#1229) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What ❔ * Database was fully split - with prover data now living in separate one * Updating `zk status prover` to work ## Why ❔ * zk status prover is helpful for local debugging of prover progress. --- infrastructure/zk/src/status.ts | 38 ++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/infrastructure/zk/src/status.ts b/infrastructure/zk/src/status.ts index 09656290d4d6..1ad437b85540 100644 --- a/infrastructure/zk/src/status.ts +++ b/infrastructure/zk/src/status.ts @@ -5,7 +5,8 @@ import { ethers } from 'ethers'; import { assert } from 'console'; // Postgres connection pool - must be initialized later - as the ENV variables are set later. -let pool: Pool | null = null; +let main_pool: Pool | null = null; +let prover_pool: Pool | null = null; const GETTER_ABI = [ 'function getTotalBatchesCommitted() view returns (uint256)', @@ -15,18 +16,20 @@ const GETTER_ABI = [ const VERIFIER_ABI = ['function verificationKeyHash() view returns (bytes32)']; -export async function query(text: string, params?: any[]): Promise { +export async function query(pool: Pool, text: string, params?: any[]): Promise { const res = await pool!.query(text, params); return res; } -async function queryAndReturnRows(text: string, params?: any[]): Promise { - const result = await query(text, params); +async function queryAndReturnRows(pool: Pool, text: string, params?: any[]): Promise { + const result = await query(pool, text, params); return result.rows; } async function getProofProgress(l1_batch_number: number) { - const result = await query('select * from prover_jobs_fri where l1_batch_number = $1', [l1_batch_number]); + const result = await query(prover_pool!, 'select * from prover_jobs_fri where l1_batch_number = $1', [ + l1_batch_number + ]); let successful = 0; let failed = 0; @@ -50,9 +53,11 @@ async function getProofProgress(l1_batch_number: number) { } }); - const compression_results = await query('select * from proof_compression_jobs_fri where l1_batch_number = $1', [ - l1_batch_number - ]); + const compression_results = await query( + prover_pool!, + 'select * from proof_compression_jobs_fri where l1_batch_number = $1', + [l1_batch_number] + ); let compression_result_string = ''; if (compression_results.rowCount == 0) { @@ -102,7 +107,10 @@ async function compareVerificationKeys() { return; } - let protocol_version = await query('select recursion_scheduler_level_vk_hash from prover_fri_protocol_versions'); + let protocol_version = await query( + prover_pool!, + 'select recursion_scheduler_level_vk_hash from prover_fri_protocol_versions' + ); if (protocol_version.rowCount != 1) { console.log(`${redStart}Got ${protocol_version.rowCount} rows with protocol versions, expected 1${resetColor}`); return; @@ -135,6 +143,7 @@ async function compareVerificationParams() { } let protocol_version = await query( + prover_pool!, 'select recursion_node_level_vk_hash, recursion_leaf_level_vk_hash, recursion_circuits_set_vks_hash from prover_fri_protocol_versions' ); if (protocol_version.rowCount != 1) { @@ -178,14 +187,18 @@ const resetColor = '\x1b[0m'; export async function statusProver() { console.log('==== FRI Prover Status ===='); - pool = new Pool({ connectionString: process.env.DATABASE_URL }); + main_pool = new Pool({ connectionString: process.env.DATABASE_URL }); + prover_pool = new Pool({ connectionString: process.env.DATABASE_PROVER_URL }); if (process.env.ETH_SENDER_SENDER_PROOF_LOADING_MODE != 'FriProofFromGcs') { console.log(`${redStart}Can only show status for FRI provers.${resetColor}`); return; } + // Fetch the first and most recent sealed batch numbers - const stateKeeperStatus = (await queryAndReturnRows('select min(number), max(number) from l1_batches'))[0]; + const stateKeeperStatus = ( + await queryAndReturnRows(main_pool, 'select min(number), max(number) from l1_batches') + )[0]; console.log(`State keeper: First batch: ${stateKeeperStatus['min']}, recent batch: ${stateKeeperStatus['max']}`); const [blockCommitted, blockVerified] = await getL1ValidatorStatus(); @@ -200,6 +213,7 @@ export async function statusProver() { `${redStart}Eth sender is ${ethSenderLag} behind. Last block committed: ${blockCommitted}. Most recent sealed state keeper batch: ${stateKeeperStatus['max']}.${resetColor}` ); } + await compareVerificationKeys(); await compareVerificationParams(); @@ -212,7 +226,7 @@ export async function statusProver() { i <= Math.min(nextBlockForVerification + 5, Number(stateKeeperStatus['max'])); i += 1 ) { - getProofProgress(i); + await getProofProgress(i); } } From ba00a148970b9dff5540e6eb4534c50cdd17ea00 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Fri, 23 Feb 2024 19:29:29 +0100 Subject: [PATCH 055/106] remove unused parameter --- core/bin/external_node/src/config/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/bin/external_node/src/config/mod.rs b/core/bin/external_node/src/config/mod.rs index 46b97550483b..88c48e39394f 100644 --- a/core/bin/external_node/src/config/mod.rs +++ b/core/bin/external_node/src/config/mod.rs @@ -391,8 +391,6 @@ pub struct RequiredENConfig { pub state_cache_path: String, /// Fast SSD path. Used as a RocksDB dir for the Merkle tree (*new* implementation). pub merkle_tree_path: String, - /// External node mode. Same as in the main node. - pub l1_batch_commit_data_generator_mode: L1BatchCommitDataGeneratorMode, } impl RequiredENConfig { From 44707721f8d61e651696cd8116f326ecaa9fafff Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 16:25:52 -0300 Subject: [PATCH 056/106] Update contracts submodule commit to matter-labs --- .gitmodules | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 71fef99dc0ba..e5defe15bf16 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "contracts"] path = contracts -url = https://github.com/LambdaClass/era-contracts.git +url = https://github.com/matter-labs/era-contracts.git branch = feat_validium_mode diff --git a/contracts b/contracts index 31707c9abc9d..bf0dbcca08ab 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 31707c9abc9d6df8be7e9e031245081ef460c194 +Subproject commit bf0dbcca08abd6a64ec4f09c7ccbfb6fe5bf0e9e From e78e9e0efac028091fc9d82d7e92f1a598a06c57 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 17:22:18 -0300 Subject: [PATCH 057/106] Update contracts submodule commit --- .gitmodules | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 53fb816b1ae7..e5ced2d8d3cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "contracts"] path = contracts url = https://github.com/LambdaClass/era-contracts.git -branch = update_validium_mode_contracts +branch = feat_get_rid_of_validium_env diff --git a/contracts b/contracts index ceb214b7650c..fd3026c58748 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit ceb214b7650c6102703a9b5569a4056fe97a3be4 +Subproject commit fd3026c5874888520018ecda5ed3da7ab2394355 From 254d87b6a14d956320d22f2af4aaf36e3fa44513 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 17:36:07 -0300 Subject: [PATCH 058/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index fd3026c58748..bf233a171cf8 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit fd3026c5874888520018ecda5ed3da7ab2394355 +Subproject commit bf233a171cf8b5c2e806612a6be1487aa36445e1 From a6959f4ede81e3cc7e59f9b41a2f5fb75f48e99f Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 17:36:29 -0300 Subject: [PATCH 059/106] Remove obscure use of VALIDIUM_MODE env --- infrastructure/zk/src/init.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index b1761d1bd61e..d068dc7fc622 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -34,7 +34,6 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { } = initArgs; await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - process.env.VALIDIUM_MODE = validiumMode.toString(); await announced('Updating mode configuration', updateConfig(validiumMode)); if (!process.env.CI && !skipEnvSetup) { await announced('Pulling images', docker.pull()); @@ -59,7 +58,10 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { await announced('Deploying L1 verifier', contract.deployVerifier([])); await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromSources()); - await announced('Deploying L1 contracts', contract.redeployL1(governorPrivateKeyArgs)); + await announced( + 'Deploying L1 contracts', + contract.redeployL1([...governorPrivateKeyArgs, ...additionalArgumentsForRedeployingL1(validiumMode)]) + ); await announced('Initializing validator', contract.initializeValidator(governorPrivateKeyArgs)); await announced( 'Deploying L2 contracts', @@ -79,7 +81,6 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { // A smaller version of `init` that "resets" the localhost environment, for which `init` was already called before. // It does less and runs much faster. export async function reinit(validiumMode: boolean) { - process.env.VALIDIUM_MODE = validiumMode.toString(); await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); await announced('Updating mode configuration', updateConfig(validiumMode)); await announced('Setting up containers', up()); @@ -93,7 +94,7 @@ export async function reinit(validiumMode: boolean) { await announced('Deploying L1 verifier', contract.deployVerifier([])); await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromSources()); - await announced('Deploying L1 contracts', contract.redeployL1([])); + await announced('Deploying L1 contracts', contract.redeployL1(additionalArgumentsForRedeployingL1(validiumMode))); await announced('Deploying L2 contracts', contract.deployL2([], true, true)); await announced('Initializing L2 WETH token', contract.initializeWethToken()); await announced('Initializing governance', contract.initializeGovernance()); @@ -102,7 +103,6 @@ export async function reinit(validiumMode: boolean) { // A lightweight version of `init` that sets up local databases, generates genesis and deploys precompiled contracts export async function lightweightInit(validiumMode: boolean) { - process.env.VALIDIUM_MODE = validiumMode.toString(); await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); await announced('Updating mode configuration', updateConfig(validiumMode)); await announced(`Setting up containers`, up()); @@ -112,7 +112,7 @@ export async function lightweightInit(validiumMode: boolean) { await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromBinary()); await announced('Deploying localhost ERC20 tokens', run.deployERC20('dev', '', '', '', [])); - await announced('Deploying L1 contracts', contract.redeployL1([])); + await announced('Deploying L1 contracts', contract.redeployL1(additionalArgumentsForRedeployingL1(validiumMode))); await announced('Initializing validator', contract.initializeValidator()); await announced('Deploying L2 contracts', contract.deployL2([], true, false)); await announced('Initializing governance', contract.initializeGovernance()); @@ -221,9 +221,6 @@ function updateConfig(validiumMode: boolean) { updateChainConfig(validiumMode); updateEthSenderConfig(validiumMode); config.compileConfig(); - let envFileContent = fs.readFileSync(process.env.ENV_FILE!).toString(); - envFileContent += `VALIDIUM_MODE=${validiumMode}\n`; - fs.writeFileSync(process.env.ENV_FILE!, envFileContent); } async function checkEnv() { @@ -239,6 +236,10 @@ async function checkEnv() { } } +function additionalArgumentsForRedeployingL1(validium: boolean) { + return validium ? ['--validium-mode'] : []; +} + export interface InitArgs { skipSubmodulesCheckout: boolean; skipEnvSetup: boolean; From 95ab24a4c0d7cf5e3026594dc3b2dc5dfb04e557 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 17:50:34 -0300 Subject: [PATCH 060/106] Revert "use a function for the function selector" This reverts commit 96035d838546dca47e26a9975cd10bd7a23a7491. --- core/lib/zksync_core/src/lib.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 4a1d57b45cda..1baae27c3b33 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -103,11 +103,6 @@ pub mod sync_layer; pub mod temp_config_store; mod utils; -/// Returns the selector of the `getPubdataPriceMode()`. -fn get_pubdata_price_mode_selector() -> Bytes { - serde_json::from_str::(r#""0x252e5966""#).unwrap() -} - /// Inserts the initial information about zkSync tokens into the database. pub async fn genesis_init( postgres_config: &PostgresConfig, @@ -641,7 +636,7 @@ pub async fn initialize_components( .call( CallRequest::builder() .to((&contracts_config).executor_facet_addr.clone()) - .data(get_pubdata_price_mode_selector()) + .data(serde_json::from_str::(r#""0x252e5966""#).unwrap()) // The selector of "getPubdataPriceMode()" .build(), ) .await From c2c464dac6f6a12aa009cd1847c3e93007e01899 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 18:21:28 -0300 Subject: [PATCH 061/106] Remove call implementation --- core/lib/eth_client/src/clients/http/query.rs | 8 ++------ core/lib/eth_client/src/clients/http/signing.rs | 13 ++----------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/core/lib/eth_client/src/clients/http/query.rs b/core/lib/eth_client/src/clients/http/query.rs index f41d9c0bdeef..d1abb74c46d6 100644 --- a/core/lib/eth_client/src/clients/http/query.rs +++ b/core/lib/eth_client/src/clients/http/query.rs @@ -7,8 +7,8 @@ use zksync_types::web3::{ ethabi, transports::Http, types::{ - Address, Block, BlockId, BlockNumber, Bytes, CallRequest, Filter, Log, Transaction, - TransactionId, TransactionReceipt, H256, U256, U64, + Address, Block, BlockId, BlockNumber, Bytes, Filter, Log, Transaction, TransactionId, + TransactionReceipt, H256, U256, U64, }, Web3, }; @@ -40,10 +40,6 @@ impl QueryClient { let transport = Http::new(node_url)?; Ok(transport.into()) } - - pub async fn call(&self, params: CallRequest) -> Result { - self.web3.eth().call(params, None).await - } } #[async_trait] diff --git a/core/lib/eth_client/src/clients/http/signing.rs b/core/lib/eth_client/src/clients/http/signing.rs index 668176378aa4..6e3dd3d223d8 100644 --- a/core/lib/eth_client/src/clients/http/signing.rs +++ b/core/lib/eth_client/src/clients/http/signing.rs @@ -11,8 +11,8 @@ use zksync_types::{ ethabi, transports::Http, types::{ - Address, Block, BlockId, BlockNumber, CallRequest, Filter, Log, Transaction, - TransactionReceipt, H160, H256, U256, U64, + Address, Block, BlockId, BlockNumber, Filter, Log, Transaction, TransactionReceipt, + H160, H256, U256, U64, }, }, L1ChainId, PackedEthSignature, EIP_1559_TX_TYPE, @@ -97,15 +97,6 @@ impl fmt::Debug for SigningClient { } } -impl SigningClient -where - S: EthereumSigner, -{ - pub async fn call(&self, params: CallRequest) -> Result { - self.query_client.call(params).await - } -} - #[async_trait] impl EthInterface for SigningClient { async fn nonce_at_for_account( From e165fac1c8767e34d18b70b1d4011dfc3893383a Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 18:21:53 -0300 Subject: [PATCH 062/106] impl Detokenize for L1BatchCommitDataGeneratorMode --- core/lib/config/src/configs/chain.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index 69c7e38793c5..28bb92e67cb9 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -1,7 +1,15 @@ use std::{str::FromStr, time::Duration}; use serde::Deserialize; -use zksync_basic_types::{network::Network, Address, Bytes, L2ChainId}; +use zksync_basic_types::{ + network::Network, + web3::{ + contract::{tokens::Detokenize, Error as Web3ContractError}, + error::Error as Web3ApiError, + ethabi, + }, + Address, Bytes, L2ChainId, +}; #[derive(Debug, Deserialize, Clone, PartialEq)] pub struct NetworkConfig { @@ -52,6 +60,19 @@ pub enum L1BatchCommitDataGeneratorMode { Validium, } +impl Detokenize for L1BatchCommitDataGeneratorMode { + fn from_tokens(tokens: Vec) -> Result { + match tokens[0] { + ethabi::Token::Bytes(ref bytes) => { + Ok(Self::from_eth_response(&Bytes::from(bytes.as_slice()))) + } + _ => Err(Web3ContractError::Api(Web3ApiError::Decoder( + "L1BatchCommitDataGeneratorMode::from_tokens".to_string(), + ))), + } + } +} + // The cases are extracted from the `PubdataPricingMode` enum in the L1 contracts, // And knowing that, in Ethereum, the response is the index of the enum case. // If the bytes are "0x0000000000000000000000000000000000000000000000000000000000000000" i want the rollup case, From 3a9e133c6fea46af0331079d072e678a6739a54e Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 18:22:13 -0300 Subject: [PATCH 063/106] Add executor_contract getter --- core/lib/contracts/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index f6bfd9c1e4a3..3ba46654a793 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -39,6 +39,8 @@ const LOADNEXT_CONTRACT_FILE: &str = "etc/contracts-test-data/artifacts-zk/contracts/loadnext/loadnext_contract.sol/LoadnextContract.json"; const LOADNEXT_SIMPLE_CONTRACT_FILE: &str = "etc/contracts-test-data/artifacts-zk/contracts/loadnext/loadnext_contract.sol/Foo.json"; +const EXECUTOR_CONTRACT_FILE: &str = + "contracts/l1-contracts/artifacts/cache/solpp-generated-contracts/zksync/facets/Executor.sol/ExecutorFacet.json"; fn read_file_to_json_value(path: impl AsRef) -> serde_json::Value { let zksync_home = std::env::var("ZKSYNC_HOME").unwrap_or_else(|_| ".".into()); @@ -91,6 +93,10 @@ pub fn verifier_contract() -> Contract { load_contract(VERIFIER_CONTRACT_FILE) } +pub fn executor_contract() -> Contract { + load_contract(EXECUTOR_CONTRACT_FILE) +} + #[derive(Debug, Clone)] pub struct TestContract { /// Contract bytecode to be used for sending deploy transaction. From da18d2445cf600f927bb72c67acac929a9b5af89 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 18:22:59 -0300 Subject: [PATCH 064/106] Call getPubdataPriceMode using Executor's contract ABI --- core/lib/zksync_core/src/lib.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 1baae27c3b33..3c43b9276f58 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -44,9 +44,8 @@ use zksync_types::{ protocol_version::{L1VerifierConfig, VerifierParams}, system_contracts::get_system_smart_contracts, web3::contract::tokens::Detokenize, - Bytes, L2ChainId, PackedEthSignature, ProtocolVersionId, + L2ChainId, PackedEthSignature, ProtocolVersionId, }; -use zksync_web3_decl::types::CallRequest; use crate::{ api_server::{ @@ -632,19 +631,14 @@ pub async fn initialize_components( } }; - let current_commitment_mode_eth_response = eth_client - .call( - CallRequest::builder() - .to((&contracts_config).executor_facet_addr.clone()) - .data(serde_json::from_str::(r#""0x252e5966""#).unwrap()) // The selector of "getPubdataPriceMode()" - .build(), - ) - .await - .context("failed to get the current commitment mode from the Ethereum")?; - - let current_commitment_mode = L1BatchCommitDataGeneratorMode::from_eth_response( - ¤t_commitment_mode_eth_response, + let args = CallFunctionArgs::new("getPubdataPriceMode", ()).for_contract( + contracts_config.executor_facet_addr, + zksync_contracts::executor_contract(), ); + let current_commitment_mode_eth_response = eth_client.call_contract_function(args).await?; + + let current_commitment_mode = + L1BatchCommitDataGeneratorMode::from_tokens(current_commitment_mode_eth_response); assert_eq!( current_commitment_mode, From 8528d0204e744a2a6f86cfb4c629ddc970ec1c38 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 18:26:28 -0300 Subject: [PATCH 065/106] Fix unhandled error --- core/lib/zksync_core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 3c43b9276f58..4fff17e6a586 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -638,7 +638,7 @@ pub async fn initialize_components( let current_commitment_mode_eth_response = eth_client.call_contract_function(args).await?; let current_commitment_mode = - L1BatchCommitDataGeneratorMode::from_tokens(current_commitment_mode_eth_response); + L1BatchCommitDataGeneratorMode::from_tokens(current_commitment_mode_eth_response)?; assert_eq!( current_commitment_mode, From bb647923f9f8ce943b61147932e3cb154b3fc600 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 18:56:40 -0300 Subject: [PATCH 066/106] Update contracts submodule commit --- .gitmodules | 2 +- contracts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 53fb816b1ae7..cb1c58774540 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "contracts"] path = contracts url = https://github.com/LambdaClass/era-contracts.git -branch = update_validium_mode_contracts +branch = feat_mode_getter_in_executor diff --git a/contracts b/contracts index 304f902f6c6d..5e54a67cccc6 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 304f902f6c6d1a2aa2c545069f41747dd71c9012 +Subproject commit 5e54a67cccc62d7a3e5b9c40cd12858f26c4dc7b From 2e240ebef937ec67a150fd7cfffe582b5c4d1b87 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 19:10:09 -0300 Subject: [PATCH 067/106] Fix L1BatchCommitDataGeneratorMode::from_tokens --- core/lib/config/src/configs/chain.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index 28bb92e67cb9..f20754837a41 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -8,7 +8,7 @@ use zksync_basic_types::{ error::Error as Web3ApiError, ethabi, }, - Address, Bytes, L2ChainId, + Address, Bytes, L2ChainId, U256, }; #[derive(Debug, Deserialize, Clone, PartialEq)] @@ -60,15 +60,27 @@ pub enum L1BatchCommitDataGeneratorMode { Validium, } +// The cases are extracted from the `PubdataPricingMode` enum in the L1 contracts, +// And knowing that, in Ethereum, the response is the index of the enum case. +// If the Uint token is 0 I want the Rollup case, +// If the Uint token is 1 I want the Validium case, +// Else, an error. impl Detokenize for L1BatchCommitDataGeneratorMode { fn from_tokens(tokens: Vec) -> Result { - match tokens[0] { - ethabi::Token::Bytes(ref bytes) => { - Ok(Self::from_eth_response(&Bytes::from(bytes.as_slice()))) + let error = Err(Web3ContractError::Api(Web3ApiError::Decoder( + "L1BatchCommitDataGeneratorMode::from_tokens".to_string(), + ))); + match tokens.as_slice() { + [ethabi::Token::Uint(enum_value)] => { + if enum_value == &U256::zero() { + Ok(L1BatchCommitDataGeneratorMode::Rollup) + } else if enum_value == &U256::one() { + Ok(L1BatchCommitDataGeneratorMode::Validium) + } else { + error + } } - _ => Err(Web3ContractError::Api(Web3ApiError::Decoder( - "L1BatchCommitDataGeneratorMode::from_tokens".to_string(), - ))), + _ => error, } } } From 19f393897b18d1dd9cb9e795f636e8cf56d4286b Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 23 Feb 2024 19:10:20 -0300 Subject: [PATCH 068/106] Add comment --- core/lib/zksync_core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 4fff17e6a586..f2f2626925b6 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -640,6 +640,7 @@ pub async fn initialize_components( let current_commitment_mode = L1BatchCommitDataGeneratorMode::from_tokens(current_commitment_mode_eth_response)?; + // contracts mode == server mode assert_eq!( current_commitment_mode, state_keeper_config.l1_batch_commit_data_generator_mode, From 629c3257a34ab3c7bc12e1a1f8694f8c3fc534e1 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Mon, 26 Feb 2024 17:23:57 +0100 Subject: [PATCH 069/106] refactor configLine into struct --- infrastructure/zk/src/init.ts | 128 ++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 30 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index b1761d1bd61e..8a0b2ea1a8f6 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -140,31 +140,55 @@ export async function submoduleUpdate() { await utils.exec('git submodule update'); } -function updateConfigFile(path: string, modeConstantValues: Record) { +interface ConfigLine { + key: string; + value: string | number | null; + section: string | null; + lineIndex?: number | null; +} + +function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { let content = fs.readFileSync(path, 'utf-8'); let lines = content.split('\n'); let addedContent: string | undefined; const lineIndices: Record = {}; + // Iterate through each line in the file for (let i = 0; i < lines.length; i++) { const line = lines[i]; + + // Check if the line does not start with '#' (comment) if (!line.startsWith('#')) { + // Using regex to match key-value pairs in the line const match = line.match(/([^=]+)=(.*)/); + if (match) { + // Extract the key and trim any leading/trailing whitespaces const key = match[1].trim(); + + // Store the index of the line where the key is found lineIndices[key] = i; } } } - for (const [key, value] of Object.entries(modeConstantValues)) { - const lineIndex = lineIndices[key]; + + // Iterate through each key-value pair in modeConstantValues + modeConstantValues.forEach((configLine) =>{ + // Get the line index for the current key from the record + const lineIndex = lineIndices[configLine.key]; + + // Check if [key, value] to append/remove is found in the file if (lineIndex !== undefined) { - if (value !== null) { - lines.splice(lineIndex, 1, `${key}=${value}`); + // If the value to insert is not null, update the line with the new value + if (configLine.value !== null) { + lines.splice(lineIndex, 1, `${configLine.key}=${configLine.value}`); } else { + // If the value is null, remove the line and update line indices lines.splice(lineIndex, 1); + + // Update line indices for keys that appear after the removed line for (const [k, index] of Object.entries(lineIndices)) { if (index > lineIndex) { lineIndices[k] = index - 1; @@ -172,54 +196,98 @@ function updateConfigFile(path: string, modeConstantValues: Record Date: Mon, 26 Feb 2024 13:47:05 -0300 Subject: [PATCH 070/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index bf233a171cf8..abb786d50645 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit bf233a171cf8b5c2e806612a6be1487aa36445e1 +Subproject commit abb786d50645b74150d85bb80e97d168b686d05d From 272e35f79fdc0a79bfec97f0449723a24893a58c Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Mon, 26 Feb 2024 19:37:04 +0100 Subject: [PATCH 071/106] update ext node config --- infrastructure/zk/src/init.ts | 112 +++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 49 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index 8a0b2ea1a8f6..3d6304124152 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -15,6 +15,7 @@ import { up } from './up'; import * as fs from 'fs'; import * as constants from './constants'; +import { Console } from 'console'; const entry = chalk.bold.yellow; const announce = chalk.yellow; @@ -22,6 +23,7 @@ const success = chalk.green; const timestamp = chalk.grey; const CHAIN_CONFIG_PATH = 'etc/env/base/chain.toml'; const ETH_SENDER_PATH = 'etc/env/base/eth_sender.toml'; +const EXT_NODE_PATH = 'etc/env/ext-node.toml'; export async function init(initArgs: InitArgs = DEFAULT_ARGS) { const { @@ -152,53 +154,78 @@ function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { let lines = content.split('\n'); let addedContent: string | undefined; const lineIndices: Record = {}; + const sectionIndices: Record = {}; // Iterate through each line in the file for (let i = 0; i < lines.length; i++) { const line = lines[i]; - // Check if the line does not start with '#' (comment) if (!line.startsWith('#')) { + // Using regex to match sections in the line + const sectionMatch = line.match(/^\s*\[([^\]]+)\]\s*$/); + if (sectionMatch) { + const section = sectionMatch[1].trim(); + sectionIndices[section] = i; + } // Using regex to match key-value pairs in the line const match = line.match(/([^=]+)=(.*)/); if (match) { - // Extract the key and trim any leading/trailing whitespaces const key = match[1].trim(); - - // Store the index of the line where the key is found lineIndices[key] = i; } } } - - - // Iterate through each key-value pair in modeConstantValues - modeConstantValues.forEach((configLine) =>{ - // Get the line index for the current key from the record + // Iterate through each config line in modeConstantValues + modeConstantValues.forEach((configLine) => { + // Get the position of the line in the file const lineIndex = lineIndices[configLine.key]; + // Get the position of the section in the file + const sectionIndex = sectionIndices[configLine.section!]; - // Check if [key, value] to append/remove is found in the file + // If config line is already in the file if (lineIndex !== undefined) { - // If the value to insert is not null, update the line with the new value + // Update value if (configLine.value !== null) { lines.splice(lineIndex, 1, `${configLine.key}=${configLine.value}`); } else { - // If the value is null, remove the line and update line indices + // Remove line lines.splice(lineIndex, 1); - - // Update line indices for keys that appear after the removed line - for (const [k, index] of Object.entries(lineIndices)) { - if (index > lineIndex) { + + //Update line indices + Object.entries(lineIndices) + .filter(([k, index]) => index > lineIndex) + .forEach(([k, index]) => { lineIndices[k] = index - 1; - } - } + }); + Object.entries(sectionIndices) + .filter(([k, index]) => index > lineIndex) + .forEach(([k, index]) => { + sectionIndices[k] = index - 1; + }); } } else { - // If it is not found, append the key-value pair to the end of the file content + // If config line is not in the file, add it if (configLine.value !== null) { - addedContent = `${configLine.key}=${configLine.value}\n`; + // If is inside a section and new config line, add the line at the start of the section + if (sectionIndex !== undefined) { + lines.splice(sectionIndex + 1, 0, `${configLine.key}=${configLine.value}`); + // Update line indices + Object.entries(lineIndices) + .filter(([k, index]) => index > sectionIndex) + .forEach(([k, index]) => { + lineIndices[k] = index + 1; + }); + Object.entries(sectionIndices) + .filter(([k, index]) => index > sectionIndex) + .forEach(([k, index]) => { + sectionIndices[k] = index + 1; + }); + } else { + // If is not inside a section, add the line at the end of the file + addedContent = `${configLine.key}=${configLine.value}\n`; + } } } }); @@ -213,48 +240,37 @@ function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { // Write the modified content back to the file fs.writeFileSync(path, content); - } - function updateChainConfig(validiumMode: boolean) { - const modeConstantValues: ConfigLine[] = [ { key: 'compute_overhead_part', - value: validiumMode - ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART - : constants.ROLLUP_COMPUTE_OVERHEAD_PART, - section: null, + value: validiumMode ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART : constants.ROLLUP_COMPUTE_OVERHEAD_PART, + section: null }, { key: 'pubdata_overhead_part', - value: validiumMode - ? constants.VALIDIUM_PUBDATA_OVERHEAD_PART - : constants.ROLLUP_PUBDATA_OVERHEAD_PART, - section: null, + value: validiumMode ? constants.VALIDIUM_PUBDATA_OVERHEAD_PART : constants.ROLLUP_PUBDATA_OVERHEAD_PART, + section: null }, { key: 'batch_overhead_l1_gas', - value: validiumMode - ? constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS - : constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, - section: null, + value: validiumMode ? constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS : constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, + section: null }, { key: 'max_pubdata_per_batch', - value: validiumMode - ? constants.VALIDIUM_MAX_PUBDATA_PER_BATCH - : constants.ROLLUP_MAX_PUBDATA_PER_BATCH, - section: null, + value: validiumMode ? constants.VALIDIUM_MAX_PUBDATA_PER_BATCH : constants.ROLLUP_MAX_PUBDATA_PER_BATCH, + section: null }, { key: 'l1_batch_commit_data_generator_mode', value: validiumMode ? constants.VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE : constants.ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE, - section: null, - }, + section: null + } ]; updateConfigFile(CHAIN_CONFIG_PATH, modeConstantValues); } @@ -264,11 +280,9 @@ function updateEthSenderConfig(validiumMode: boolean) { const modeConstantValues: ConfigLine[] = [ { key: 'l1_gas_per_pubdata_byte', - value: validiumMode - ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE - : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE, - section: 'en', - }, + value: validiumMode ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE, + section: null + } ]; updateConfigFile(ETH_SENDER_PATH, modeConstantValues); } @@ -278,10 +292,10 @@ function updateExtNodeConfig(validiumMode: boolean) { { key: 'l1_batch_commit_data_generator_mode', value: validiumMode ? 'Validium' : null, - section: 'en', - }, + section: validiumMode ? 'en' : null + } ]; - updateConfigFile('etc/env/ext-node.toml', modeConstantValues); + updateConfigFile(EXT_NODE_PATH, modeConstantValues); } function updateConfig(validiumMode: boolean) { From d5fdb5ced488d8d3b4f2b0239fdb4a13c829ac40 Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Mon, 26 Feb 2024 19:47:47 +0100 Subject: [PATCH 072/106] rename var --- infrastructure/zk/src/init.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index 3d6304124152..68c3d5025dd7 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -149,7 +149,7 @@ interface ConfigLine { lineIndex?: number | null; } -function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { +function updateConfigFile(path: string, updatedConfigLines: ConfigLine[]) { let content = fs.readFileSync(path, 'utf-8'); let lines = content.split('\n'); let addedContent: string | undefined; @@ -177,8 +177,8 @@ function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { } } - // Iterate through each config line in modeConstantValues - modeConstantValues.forEach((configLine) => { + // Iterate through each config line in updatedConfigLines + updatedConfigLines.forEach((configLine) => { // Get the position of the line in the file const lineIndex = lineIndices[configLine.key]; // Get the position of the section in the file @@ -243,7 +243,7 @@ function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { } function updateChainConfig(validiumMode: boolean) { - const modeConstantValues: ConfigLine[] = [ + const updatedConfigLines: ConfigLine[] = [ { key: 'compute_overhead_part', value: validiumMode ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART : constants.ROLLUP_COMPUTE_OVERHEAD_PART, @@ -272,30 +272,30 @@ function updateChainConfig(validiumMode: boolean) { section: null } ]; - updateConfigFile(CHAIN_CONFIG_PATH, modeConstantValues); + updateConfigFile(CHAIN_CONFIG_PATH, updatedConfigLines); } function updateEthSenderConfig(validiumMode: boolean) { // This constant is used in validium mode and is deleted in rollup mode // In order to pass the existing integration tests - const modeConstantValues: ConfigLine[] = [ + const updatedConfigLines: ConfigLine[] = [ { key: 'l1_gas_per_pubdata_byte', value: validiumMode ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE, section: null } ]; - updateConfigFile(ETH_SENDER_PATH, modeConstantValues); + updateConfigFile(ETH_SENDER_PATH, updatedConfigLines); } function updateExtNodeConfig(validiumMode: boolean) { - const modeConstantValues: ConfigLine[] = [ + const updatedConfigLines: ConfigLine[] = [ { key: 'l1_batch_commit_data_generator_mode', value: validiumMode ? 'Validium' : null, section: validiumMode ? 'en' : null } ]; - updateConfigFile(EXT_NODE_PATH, modeConstantValues); + updateConfigFile(EXT_NODE_PATH, updatedConfigLines); } function updateConfig(validiumMode: boolean) { From bb42d5bdf8628cc4a69cf73fb5173047b436080c Mon Sep 17 00:00:00 2001 From: ilitteri Date: Mon, 26 Feb 2024 18:41:28 -0300 Subject: [PATCH 073/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index abb786d50645..a99c79683c18 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit abb786d50645b74150d85bb80e97d168b686d05d +Subproject commit a99c79683c18cbda8f23b1310255d3710ffe1697 From 213b2b12f4cc7cd984b7c945666db844f44957fe Mon Sep 17 00:00:00 2001 From: ilitteri Date: Mon, 26 Feb 2024 19:39:57 -0300 Subject: [PATCH 074/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 5e54a67cccc6..6da63cc98fec 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 5e54a67cccc62d7a3e5b9c40cd12858f26c4dc7b +Subproject commit 6da63cc98fec09a52af766e5f3d76044b8198536 From c99c61e94cc48390b1c4c8edcd3ea084f518ac84 Mon Sep 17 00:00:00 2001 From: Jordi Date: Tue, 27 Feb 2024 11:28:31 +0100 Subject: [PATCH 075/106] Stash --- core/lib/protobuf_config/src/tests.rs | 82 ++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/core/lib/protobuf_config/src/tests.rs b/core/lib/protobuf_config/src/tests.rs index de4803a10085..48c011b26e6a 100644 --- a/core/lib/protobuf_config/src/tests.rs +++ b/core/lib/protobuf_config/src/tests.rs @@ -1,8 +1,9 @@ use pretty_assertions::assert_eq; use rand::Rng; +use testonly::{Gen, RandomConfig}; use zksync_config::testonly; -use crate::{proto, repr::ProtoRepr}; +use crate::{proto, proto::FeeModelVersion::V1, repr::ProtoRepr}; fn encode(msg: &P::Type) -> Vec { let msg = P::build(msg); @@ -90,3 +91,82 @@ fn test_encoding() { encode_decode::(rng); encode_decode::(rng); } + +#[test] +fn test_encoding_state_keeper_mode() { + // Test Rollup mode + let mode_rollup = proto::L1BatchCommitDataGeneratorMode::Rollup; + encode_decode_mode::(&mode_rollup); + + // Test Validium mode + let mode_validium = proto::L1BatchCommitDataGeneratorMode::Validium; + encode_decode_mode::(&mode_validium); +} + +#[track_caller] +fn encode_decode_mode(mode: &proto::L1BatchCommitDataGeneratorMode) +where + P::Type: PartialEq + std::fmt::Debug + testonly::RandomConfig, +{ + for required_only in [false, true] { + // Manually set the L1BatchCommitDataGeneratorMode + let mut state_keeper = generate_mode(mode); + dbg!(state_keeper); + + let rng = &mut rand::thread_rng(); + let want: P::Type = testonly::Gen { + rng, + required_only, + decimal_fractions: false, + } + .gen(); + dbg!(want); + assert_eq!(1, 2); + //let got = decode::

    (&encode::

    (&want)).unwrap(); + + // let got = decode::

    (&encode::

    (&state_keeper)).unwrap(); + // assert_eq!(&state_keeper, &got, "binary encoding"); + + // let got = decode_json::

    (&encode_json::

    (&state_keeper)).unwrap(); + // assert_eq!(&state_keeper, &got, "json encoding"); + // + } +} + +fn generate_mode(mode: &proto::L1BatchCommitDataGeneratorMode) -> proto::StateKeeper { + proto::StateKeeper { + transaction_slots: Some(10926497003267881492), + block_commit_deadline_ms: Some(10947007445086036797), + miniblock_commit_deadline_ms: Some(9103314936350460727), + miniblock_seal_queue_capacity: Some(6906530626745786909), + max_single_tx_gas: Some(2785542050), + max_allowed_l2_tx_gas_limit: Some(1183074970), + reject_tx_at_geometry_percentage: Some(0.5296344133371791), + reject_tx_at_eth_params_percentage: Some(0.8773607433255183), + reject_tx_at_gas_percentage: Some(0.5289453936748325), + close_block_at_geometry_percentage: Some(0.6479326814884391), + close_block_at_eth_params_percentage: Some(0.21958980771195413), + close_block_at_gas_percentage: Some(0.5229693273318018), + fee_account_addr: Some( + [ + 153, 251, 1, 240, 243, 248, 139, 100, 180, 119, 34, 199, 146, 251, 165, 177, 250, + 52, 209, 52, + ] + .into(), + ), + minimal_l2_gas_price: Some(2703211627494097776), + compute_overhead_part: Some(0.6857318990462495), + pubdata_overhead_part: Some(0.12953109152591813), + batch_overhead_l1_gas: Some(15518551973209220528), + max_gas_per_batch: Some(15859976163468884008), + max_pubdata_per_batch: Some(11012258501587398219), + fee_model_version: Some(V1.into()), + validation_computational_gas_limit: Some(2619723581), + save_call_traces: Some(true), + virtual_blocks_interval: Some(1113108050), + virtual_blocks_per_miniblock: Some(756446353), + upload_witness_inputs_to_gcs: Some(true), + enum_index_migration_chunk_size: Some(3905631822449257186), + l1_batch_commit_data_generator_mode: Some(mode.clone().into()), + } +} From 0a048053cd45980cec0cd441d0d83f3bdc63c8e0 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Tue, 27 Feb 2024 10:19:53 -0300 Subject: [PATCH 076/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index 6da63cc98fec..798a9fbb6871 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit 6da63cc98fec09a52af766e5f3d76044b8198536 +Subproject commit 798a9fbb68716fe0dbd2bb70adfb9d1c6dd08b87 From fe24f890d6ab2b8d867af39b543fbdc731e1d7f9 Mon Sep 17 00:00:00 2001 From: Jordi Date: Wed, 28 Feb 2024 10:25:51 +0100 Subject: [PATCH 077/106] Check mode --- core/lib/protobuf_config/src/tests.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/core/lib/protobuf_config/src/tests.rs b/core/lib/protobuf_config/src/tests.rs index 48c011b26e6a..a479d720abf7 100644 --- a/core/lib/protobuf_config/src/tests.rs +++ b/core/lib/protobuf_config/src/tests.rs @@ -110,8 +110,19 @@ where { for required_only in [false, true] { // Manually set the L1BatchCommitDataGeneratorMode - let mut state_keeper = generate_mode(mode); - dbg!(state_keeper); + let state_keeper = generate_mode(mode); + + // Transform to StateKeeperConfig + let state_keeper_config = state_keeper.read().unwrap(); + dbg!(&state_keeper_config); + + // Check that mode in the StateKeeperConfig matches the tested mode + let mode_str = format!("{:#?}", mode); + let mode_skc_str = format!( + "{:#?}", + &state_keeper_config.l1_batch_commit_data_generator_mode + ); + assert_eq!(mode_str, mode_skc_str, "check mode"); let rng = &mut rand::thread_rng(); let want: P::Type = testonly::Gen { @@ -120,9 +131,10 @@ where decimal_fractions: false, } .gen(); - dbg!(want); + + dbg!(&want); assert_eq!(1, 2); - //let got = decode::

    (&encode::

    (&want)).unwrap(); + let got = decode::

    (&encode::

    (&want)).unwrap(); // let got = decode::

    (&encode::

    (&state_keeper)).unwrap(); // assert_eq!(&state_keeper, &got, "binary encoding"); @@ -167,6 +179,6 @@ fn generate_mode(mode: &proto::L1BatchCommitDataGeneratorMode) -> proto::StateKe virtual_blocks_per_miniblock: Some(756446353), upload_witness_inputs_to_gcs: Some(true), enum_index_migration_chunk_size: Some(3905631822449257186), - l1_batch_commit_data_generator_mode: Some(mode.clone().into()), + l1_batch_commit_data_generator_mode: Some((*mode).into()), } } From f9025235dad265e5d17284622c5134874b29dc08 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 10:35:15 -0300 Subject: [PATCH 078/106] Remove unused function --- core/lib/config/src/configs/chain.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index f20754837a41..fc5f137dc03a 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -85,25 +85,6 @@ impl Detokenize for L1BatchCommitDataGeneratorMode { } } -// The cases are extracted from the `PubdataPricingMode` enum in the L1 contracts, -// And knowing that, in Ethereum, the response is the index of the enum case. -// If the bytes are "0x0000000000000000000000000000000000000000000000000000000000000000" i want the rollup case, -// If the bytes are "0x0000000000000000000000000000000000000000000000000000000000000001" i want the validium case, -// Else, an error. -impl L1BatchCommitDataGeneratorMode { - pub fn from_eth_response(response: &Bytes) -> Self { - match &response.0.as_slice() { - &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] => { - Self::Rollup - } - &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1] => { - Self::Validium - } - _response => panic!("Invalid response: {:?}", _response), - } - } -} - #[derive(Debug, Deserialize, Clone, PartialEq, Default)] pub struct StateKeeperConfig { /// The max number of slots for txs in a block before it should be sealed by the slots sealer. From cc34e8101cf9da1e6344275cd32f58ebcded33c7 Mon Sep 17 00:00:00 2001 From: Jordi Date: Wed, 28 Feb 2024 16:11:48 +0100 Subject: [PATCH 079/106] Remove unnecessary test and TODOs --- core/lib/config/src/testonly.rs | 4 +- core/lib/protobuf_config/src/chain.rs | 2 - core/lib/protobuf_config/src/tests.rs | 94 +-------------------------- 3 files changed, 2 insertions(+), 98 deletions(-) diff --git a/core/lib/config/src/testonly.rs b/core/lib/config/src/testonly.rs index 823c5fc1486a..e4d246995de0 100644 --- a/core/lib/config/src/testonly.rs +++ b/core/lib/config/src/testonly.rs @@ -286,7 +286,6 @@ impl RandomConfig for configs::chain::StateKeeperConfig { virtual_blocks_per_miniblock: g.gen(), upload_witness_inputs_to_gcs: g.gen(), enum_index_migration_chunk_size: g.gen(), - // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. l1_batch_commit_data_generator_mode: g.gen(), } } @@ -497,8 +496,7 @@ impl RandomConfig for configs::eth_sender::GasAdjusterConfig { internal_enforced_l1_gas_price: g.gen(), poll_period: g.gen(), max_l1_gas_price: g.gen(), - // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. - l1_gas_per_pubdata_byte: g.gen(), + l1_gas_per_pubdata_byte: 17, } } } diff --git a/core/lib/protobuf_config/src/chain.rs b/core/lib/protobuf_config/src/chain.rs index c59f7fa86cd4..99de9bc98024 100644 --- a/core/lib/protobuf_config/src/chain.rs +++ b/core/lib/protobuf_config/src/chain.rs @@ -161,7 +161,6 @@ impl ProtoRepr for proto::StateKeeper { l1_batch_commit_data_generator_mode: required( &self.l1_batch_commit_data_generator_mode, ) - // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. .and_then(|x| Ok(proto::L1BatchCommitDataGeneratorMode::try_from(*x)?)) .context("l1_batch_commit_data_generator_mode")? .parse(), @@ -201,7 +200,6 @@ impl ProtoRepr for proto::StateKeeper { .enum_index_migration_chunk_size .as_ref() .map(|x| (*x).try_into().unwrap()), - // TODO: this should depend on the mode (Validium or Rollup), but the tests are not adapted yet for this. l1_batch_commit_data_generator_mode: Some( proto::L1BatchCommitDataGeneratorMode::new( &this.l1_batch_commit_data_generator_mode, diff --git a/core/lib/protobuf_config/src/tests.rs b/core/lib/protobuf_config/src/tests.rs index a479d720abf7..de4803a10085 100644 --- a/core/lib/protobuf_config/src/tests.rs +++ b/core/lib/protobuf_config/src/tests.rs @@ -1,9 +1,8 @@ use pretty_assertions::assert_eq; use rand::Rng; -use testonly::{Gen, RandomConfig}; use zksync_config::testonly; -use crate::{proto, proto::FeeModelVersion::V1, repr::ProtoRepr}; +use crate::{proto, repr::ProtoRepr}; fn encode(msg: &P::Type) -> Vec { let msg = P::build(msg); @@ -91,94 +90,3 @@ fn test_encoding() { encode_decode::(rng); encode_decode::(rng); } - -#[test] -fn test_encoding_state_keeper_mode() { - // Test Rollup mode - let mode_rollup = proto::L1BatchCommitDataGeneratorMode::Rollup; - encode_decode_mode::(&mode_rollup); - - // Test Validium mode - let mode_validium = proto::L1BatchCommitDataGeneratorMode::Validium; - encode_decode_mode::(&mode_validium); -} - -#[track_caller] -fn encode_decode_mode(mode: &proto::L1BatchCommitDataGeneratorMode) -where - P::Type: PartialEq + std::fmt::Debug + testonly::RandomConfig, -{ - for required_only in [false, true] { - // Manually set the L1BatchCommitDataGeneratorMode - let state_keeper = generate_mode(mode); - - // Transform to StateKeeperConfig - let state_keeper_config = state_keeper.read().unwrap(); - dbg!(&state_keeper_config); - - // Check that mode in the StateKeeperConfig matches the tested mode - let mode_str = format!("{:#?}", mode); - let mode_skc_str = format!( - "{:#?}", - &state_keeper_config.l1_batch_commit_data_generator_mode - ); - assert_eq!(mode_str, mode_skc_str, "check mode"); - - let rng = &mut rand::thread_rng(); - let want: P::Type = testonly::Gen { - rng, - required_only, - decimal_fractions: false, - } - .gen(); - - dbg!(&want); - assert_eq!(1, 2); - let got = decode::

    (&encode::

    (&want)).unwrap(); - - // let got = decode::

    (&encode::

    (&state_keeper)).unwrap(); - // assert_eq!(&state_keeper, &got, "binary encoding"); - - // let got = decode_json::

    (&encode_json::

    (&state_keeper)).unwrap(); - // assert_eq!(&state_keeper, &got, "json encoding"); - // - } -} - -fn generate_mode(mode: &proto::L1BatchCommitDataGeneratorMode) -> proto::StateKeeper { - proto::StateKeeper { - transaction_slots: Some(10926497003267881492), - block_commit_deadline_ms: Some(10947007445086036797), - miniblock_commit_deadline_ms: Some(9103314936350460727), - miniblock_seal_queue_capacity: Some(6906530626745786909), - max_single_tx_gas: Some(2785542050), - max_allowed_l2_tx_gas_limit: Some(1183074970), - reject_tx_at_geometry_percentage: Some(0.5296344133371791), - reject_tx_at_eth_params_percentage: Some(0.8773607433255183), - reject_tx_at_gas_percentage: Some(0.5289453936748325), - close_block_at_geometry_percentage: Some(0.6479326814884391), - close_block_at_eth_params_percentage: Some(0.21958980771195413), - close_block_at_gas_percentage: Some(0.5229693273318018), - fee_account_addr: Some( - [ - 153, 251, 1, 240, 243, 248, 139, 100, 180, 119, 34, 199, 146, 251, 165, 177, 250, - 52, 209, 52, - ] - .into(), - ), - minimal_l2_gas_price: Some(2703211627494097776), - compute_overhead_part: Some(0.6857318990462495), - pubdata_overhead_part: Some(0.12953109152591813), - batch_overhead_l1_gas: Some(15518551973209220528), - max_gas_per_batch: Some(15859976163468884008), - max_pubdata_per_batch: Some(11012258501587398219), - fee_model_version: Some(V1.into()), - validation_computational_gas_limit: Some(2619723581), - save_call_traces: Some(true), - virtual_blocks_interval: Some(1113108050), - virtual_blocks_per_miniblock: Some(756446353), - upload_witness_inputs_to_gcs: Some(true), - enum_index_migration_chunk_size: Some(3905631822449257186), - l1_batch_commit_data_generator_mode: Some((*mode).into()), - } -} From d35e74d4569b6be0834560f51e965683777de5ea Mon Sep 17 00:00:00 2001 From: toni-calvin Date: Wed, 28 Feb 2024 17:42:01 +0100 Subject: [PATCH 080/106] add ext-node-validium.toml file --- .gitignore | 1 + etc/env/ext-node-validium.toml | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 etc/env/ext-node-validium.toml diff --git a/.gitignore b/.gitignore index 59a209d2dc5d..110e86ac4860 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ Cargo.lock !/etc/env/docker.toml !/etc/env/ext-node.toml !/etc/env/ext-node-docker.toml +!/etc/env/ext-node-validium.toml !/etc/env/consensus_config.json !/etc/env/en_consensus_config.json /etc/tokens/localhost.json diff --git a/etc/env/ext-node-validium.toml b/etc/env/ext-node-validium.toml new file mode 100644 index 000000000000..6486115b67e2 --- /dev/null +++ b/etc/env/ext-node-validium.toml @@ -0,0 +1,5 @@ +[en] +l1_batch_commit_data_generator_mode = "Validium" + +[_metadata] +base = ["ext-node.toml"] From 15d31f62285d01688a517140cf9c48265c9fe7b0 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 15:26:08 -0300 Subject: [PATCH 081/106] Update how the config is set now --- etc/env/dev_validium.toml | 14 +++++++ infrastructure/zk/src/config.ts | 70 --------------------------------- infrastructure/zk/src/init.ts | 3 -- 3 files changed, 14 insertions(+), 73 deletions(-) create mode 100644 etc/env/dev_validium.toml diff --git a/etc/env/dev_validium.toml b/etc/env/dev_validium.toml new file mode 100644 index 000000000000..1af0aa17893a --- /dev/null +++ b/etc/env/dev_validium.toml @@ -0,0 +1,14 @@ +[chain.state_keeper] +compute_overhead_part=1.0 +pubdata_overhead_part=0.0 +batch_overhead_l1_gas=1000000 +max_pubdata_per_batch=1000000000000 +fee_model_version="V2" +l1_batch_commit_data_generator_mode="Validium" + +# This override will be removed soon but it is needed for now. +[eth_sender.gas_adjuster] +l1_gas_per_pubdata_byte=0 + +[_metadata] +base = ['dev.toml'] diff --git a/infrastructure/zk/src/config.ts b/infrastructure/zk/src/config.ts index 90932df261fc..2541055bb8c0 100644 --- a/infrastructure/zk/src/config.ts +++ b/infrastructure/zk/src/config.ts @@ -93,65 +93,6 @@ function loadConfigRecursive(config: object, configPath: string, calledFrom: str deepExtend(config, overrides); } -// Updates config file by overriding values received as param -function updateConfigFile(path: string, modeConstantValues: Record) { - let content = fs.readFileSync(path, 'utf-8'); - let lines = content.split('\n'); - let addedContent: string | undefined; - const lineIndices: Record = {}; - - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (!line.startsWith('#')) { - const match = line.match(/([^=]+)=(.*)/); - if (match) { - const key = match[1].trim(); - lineIndices[key] = i; - } - } - } - - for (const [key, value] of Object.entries(modeConstantValues)) { - const lineIndex = lineIndices[key]; - - if (lineIndex !== undefined) { - if (value !== null) { - lines.splice(lineIndex, 1, `${key}=${value}`); - } else { - lines.splice(lineIndex, 1); - for (const [k, index] of Object.entries(lineIndices)) { - if (index > lineIndex) { - lineIndices[k] = index - 1; - } - } - } - } else { - if (value !== null) { - addedContent = `${key}=${value}\n`; - } - } - } - - content = lines.join('\n'); - - if (addedContent) { - content += addedContent; - } - - fs.writeFileSync(path, content); -} - -function updateChainConfig(validiumMode: boolean) { - const modeConstantValues = config_constants.getChainConfigConstants(validiumMode); - updateConfigFile(config_constants.CHAIN_CONFIG_PATH, modeConstantValues); -} - -function updateEthSenderConfig(validiumMode: boolean) { - // This constant is used in validium mode and is deleted in rollup mode in order to pass the existing integration tests - const modeConstantValues = config_constants.getEthSenderConfigConstants(validiumMode); - updateConfigFile(config_constants.ETH_SENDER_PATH, modeConstantValues); -} - export function printAllConfigs(environment?: string) { const config = loadConfig(environment); console.log(`${JSON.stringify(config, null, 2)}`); @@ -172,17 +113,6 @@ export function compileConfig(environment?: string) { console.log(`Configs compiled for ${environment}`); } -// If running ValidiumMode config files should be updated and recompiled to get the right constant values -// UpdateConfig should be run on init -export function updateConfig(validiumMode: boolean) { - updateChainConfig(validiumMode); - updateEthSenderConfig(validiumMode); - compileConfig(); - let envFileContent = fs.readFileSync(process.env.ENV_FILE!).toString(); - envFileContent += `VALIDIUM_MODE=${validiumMode}\n`; - fs.writeFileSync(process.env.ENV_FILE!, envFileContent); -} - export const command = new Command('config').description('config management'); command.command('load [environment]').description('load the config for a certain environment').action(printAllConfigs); diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index b55c1e4f3222..c15c319ab09d 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -32,7 +32,6 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); process.env.VALIDIUM_MODE = validiumMode.toString(); - await announced('Updating mode configuration', config.updateConfig(validiumMode)); if (!process.env.CI && !skipEnvSetup) { await announced('Pulling images', docker.pull()); await announced('Checking environment', checkEnv()); @@ -78,7 +77,6 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { export async function reinit(validiumMode: boolean) { process.env.VALIDIUM_MODE = validiumMode.toString(); await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - await announced('Updating mode configuration', config.updateConfig(validiumMode)); await announced('Setting up containers', up()); await announced('Compiling JS packages', run.yarn()); await announced('Compile l2 contracts', compiler.compileAll()); @@ -101,7 +99,6 @@ export async function reinit(validiumMode: boolean) { export async function lightweightInit(validiumMode: boolean) { process.env.VALIDIUM_MODE = validiumMode.toString(); await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - await announced('Updating mode configuration', config.updateConfig(validiumMode)); await announced(`Setting up containers`, up()); await announced('Clean rocksdb', clean('db')); await announced('Clean backups', clean('backups')); From 4b9565743637af88f4535a1c49a8e916da2de0b4 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 15:36:31 -0300 Subject: [PATCH 082/106] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 59a209d2dc5d..6a4a4e879d6a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ Cargo.lock /etc/env/* !/etc/env/base !/etc/env/dev.toml +!/etc/env/dev_validium.toml !/etc/env/docker.toml !/etc/env/ext-node.toml !/etc/env/ext-node-docker.toml From 89c32ffbb78c0842554137a92024012636d6e183 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 15:44:25 -0300 Subject: [PATCH 083/106] Revert "rename var" This reverts commit d5fdb5ced488d8d3b4f2b0239fdb4a13c829ac40. --- infrastructure/zk/src/init.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index 2cd6d508572e..8002cfa24565 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -150,7 +150,7 @@ interface ConfigLine { lineIndex?: number | null; } -function updateConfigFile(path: string, updatedConfigLines: ConfigLine[]) { +function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { let content = fs.readFileSync(path, 'utf-8'); let lines = content.split('\n'); let addedContent: string | undefined; @@ -178,8 +178,8 @@ function updateConfigFile(path: string, updatedConfigLines: ConfigLine[]) { } } - // Iterate through each config line in updatedConfigLines - updatedConfigLines.forEach((configLine) => { + // Iterate through each config line in modeConstantValues + modeConstantValues.forEach((configLine) => { // Get the position of the line in the file const lineIndex = lineIndices[configLine.key]; // Get the position of the section in the file @@ -244,7 +244,7 @@ function updateConfigFile(path: string, updatedConfigLines: ConfigLine[]) { } function updateChainConfig(validiumMode: boolean) { - const updatedConfigLines: ConfigLine[] = [ + const modeConstantValues: ConfigLine[] = [ { key: 'compute_overhead_part', value: validiumMode ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART : constants.ROLLUP_COMPUTE_OVERHEAD_PART, @@ -273,30 +273,30 @@ function updateChainConfig(validiumMode: boolean) { section: null } ]; - updateConfigFile(CHAIN_CONFIG_PATH, updatedConfigLines); + updateConfigFile(CHAIN_CONFIG_PATH, modeConstantValues); } function updateEthSenderConfig(validiumMode: boolean) { // This constant is used in validium mode and is deleted in rollup mode // In order to pass the existing integration tests - const updatedConfigLines: ConfigLine[] = [ + const modeConstantValues: ConfigLine[] = [ { key: 'l1_gas_per_pubdata_byte', value: validiumMode ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE, section: null } ]; - updateConfigFile(ETH_SENDER_PATH, updatedConfigLines); + updateConfigFile(ETH_SENDER_PATH, modeConstantValues); } function updateExtNodeConfig(validiumMode: boolean) { - const updatedConfigLines: ConfigLine[] = [ + const modeConstantValues: ConfigLine[] = [ { key: 'l1_batch_commit_data_generator_mode', value: validiumMode ? 'Validium' : null, section: validiumMode ? 'en' : null } ]; - updateConfigFile(EXT_NODE_PATH, updatedConfigLines); + updateConfigFile(EXT_NODE_PATH, modeConstantValues); } function updateConfig(validiumMode: boolean) { From b99e4b0e959e2e040676ce6710a009cea563b24b Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 15:44:32 -0300 Subject: [PATCH 084/106] Revert "update ext node config" This reverts commit 272e35f79fdc0a79bfec97f0449723a24893a58c. --- infrastructure/zk/src/init.ts | 112 +++++++++++++++------------------- 1 file changed, 49 insertions(+), 63 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index 8002cfa24565..e352b53e3165 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -15,7 +15,6 @@ import { up } from './up'; import * as fs from 'fs'; import * as constants from './constants'; -import { Console } from 'console'; const entry = chalk.bold.yellow; const announce = chalk.yellow; @@ -23,7 +22,6 @@ const success = chalk.green; const timestamp = chalk.grey; const CHAIN_CONFIG_PATH = 'etc/env/base/chain.toml'; const ETH_SENDER_PATH = 'etc/env/base/eth_sender.toml'; -const EXT_NODE_PATH = 'etc/env/ext-node.toml'; export async function init(initArgs: InitArgs = DEFAULT_ARGS) { const { @@ -155,78 +153,53 @@ function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { let lines = content.split('\n'); let addedContent: string | undefined; const lineIndices: Record = {}; - const sectionIndices: Record = {}; // Iterate through each line in the file for (let i = 0; i < lines.length; i++) { const line = lines[i]; + // Check if the line does not start with '#' (comment) if (!line.startsWith('#')) { - // Using regex to match sections in the line - const sectionMatch = line.match(/^\s*\[([^\]]+)\]\s*$/); - if (sectionMatch) { - const section = sectionMatch[1].trim(); - sectionIndices[section] = i; - } // Using regex to match key-value pairs in the line const match = line.match(/([^=]+)=(.*)/); if (match) { + // Extract the key and trim any leading/trailing whitespaces const key = match[1].trim(); + + // Store the index of the line where the key is found lineIndices[key] = i; } } } - // Iterate through each config line in modeConstantValues - modeConstantValues.forEach((configLine) => { - // Get the position of the line in the file + + + // Iterate through each key-value pair in modeConstantValues + modeConstantValues.forEach((configLine) =>{ + // Get the line index for the current key from the record const lineIndex = lineIndices[configLine.key]; - // Get the position of the section in the file - const sectionIndex = sectionIndices[configLine.section!]; - // If config line is already in the file + // Check if [key, value] to append/remove is found in the file if (lineIndex !== undefined) { - // Update value + // If the value to insert is not null, update the line with the new value if (configLine.value !== null) { lines.splice(lineIndex, 1, `${configLine.key}=${configLine.value}`); } else { - // Remove line + // If the value is null, remove the line and update line indices lines.splice(lineIndex, 1); - - //Update line indices - Object.entries(lineIndices) - .filter(([k, index]) => index > lineIndex) - .forEach(([k, index]) => { + + // Update line indices for keys that appear after the removed line + for (const [k, index] of Object.entries(lineIndices)) { + if (index > lineIndex) { lineIndices[k] = index - 1; - }); - Object.entries(sectionIndices) - .filter(([k, index]) => index > lineIndex) - .forEach(([k, index]) => { - sectionIndices[k] = index - 1; - }); + } + } } } else { - // If config line is not in the file, add it + // If it is not found, append the key-value pair to the end of the file content if (configLine.value !== null) { - // If is inside a section and new config line, add the line at the start of the section - if (sectionIndex !== undefined) { - lines.splice(sectionIndex + 1, 0, `${configLine.key}=${configLine.value}`); - // Update line indices - Object.entries(lineIndices) - .filter(([k, index]) => index > sectionIndex) - .forEach(([k, index]) => { - lineIndices[k] = index + 1; - }); - Object.entries(sectionIndices) - .filter(([k, index]) => index > sectionIndex) - .forEach(([k, index]) => { - sectionIndices[k] = index + 1; - }); - } else { - // If is not inside a section, add the line at the end of the file - addedContent = `${configLine.key}=${configLine.value}\n`; - } + addedContent = `${configLine.key}=${configLine.value}\n`; } } }); @@ -241,37 +214,48 @@ function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { // Write the modified content back to the file fs.writeFileSync(path, content); + } + function updateChainConfig(validiumMode: boolean) { + const modeConstantValues: ConfigLine[] = [ { key: 'compute_overhead_part', - value: validiumMode ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART : constants.ROLLUP_COMPUTE_OVERHEAD_PART, - section: null + value: validiumMode + ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART + : constants.ROLLUP_COMPUTE_OVERHEAD_PART, + section: null, }, { key: 'pubdata_overhead_part', - value: validiumMode ? constants.VALIDIUM_PUBDATA_OVERHEAD_PART : constants.ROLLUP_PUBDATA_OVERHEAD_PART, - section: null + value: validiumMode + ? constants.VALIDIUM_PUBDATA_OVERHEAD_PART + : constants.ROLLUP_PUBDATA_OVERHEAD_PART, + section: null, }, { key: 'batch_overhead_l1_gas', - value: validiumMode ? constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS : constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, - section: null + value: validiumMode + ? constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS + : constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, + section: null, }, { key: 'max_pubdata_per_batch', - value: validiumMode ? constants.VALIDIUM_MAX_PUBDATA_PER_BATCH : constants.ROLLUP_MAX_PUBDATA_PER_BATCH, - section: null + value: validiumMode + ? constants.VALIDIUM_MAX_PUBDATA_PER_BATCH + : constants.ROLLUP_MAX_PUBDATA_PER_BATCH, + section: null, }, { key: 'l1_batch_commit_data_generator_mode', value: validiumMode ? constants.VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE : constants.ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE, - section: null - } + section: null, + }, ]; updateConfigFile(CHAIN_CONFIG_PATH, modeConstantValues); } @@ -281,9 +265,11 @@ function updateEthSenderConfig(validiumMode: boolean) { const modeConstantValues: ConfigLine[] = [ { key: 'l1_gas_per_pubdata_byte', - value: validiumMode ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE, - section: null - } + value: validiumMode + ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE + : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE, + section: 'en', + }, ]; updateConfigFile(ETH_SENDER_PATH, modeConstantValues); } @@ -293,10 +279,10 @@ function updateExtNodeConfig(validiumMode: boolean) { { key: 'l1_batch_commit_data_generator_mode', value: validiumMode ? 'Validium' : null, - section: validiumMode ? 'en' : null - } + section: 'en', + }, ]; - updateConfigFile(EXT_NODE_PATH, modeConstantValues); + updateConfigFile('etc/env/ext-node.toml', modeConstantValues); } function updateConfig(validiumMode: boolean) { From 2dcebfd8f8cb5f72fc6b7217927d95ba796e0a9f Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 15:44:42 -0300 Subject: [PATCH 085/106] Revert "refactor configLine into struct" This reverts commit 629c3257a34ab3c7bc12e1a1f8694f8c3fc534e1. --- infrastructure/zk/src/init.ts | 128 ++++++++-------------------------- 1 file changed, 30 insertions(+), 98 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index e352b53e3165..b4436ca5741e 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -141,55 +141,31 @@ export async function submoduleUpdate() { await utils.exec('git submodule update'); } -interface ConfigLine { - key: string; - value: string | number | null; - section: string | null; - lineIndex?: number | null; -} - -function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { +function updateConfigFile(path: string, modeConstantValues: Record) { let content = fs.readFileSync(path, 'utf-8'); let lines = content.split('\n'); let addedContent: string | undefined; const lineIndices: Record = {}; - // Iterate through each line in the file for (let i = 0; i < lines.length; i++) { const line = lines[i]; - - // Check if the line does not start with '#' (comment) if (!line.startsWith('#')) { - // Using regex to match key-value pairs in the line const match = line.match(/([^=]+)=(.*)/); - if (match) { - // Extract the key and trim any leading/trailing whitespaces const key = match[1].trim(); - - // Store the index of the line where the key is found lineIndices[key] = i; } } } + for (const [key, value] of Object.entries(modeConstantValues)) { + const lineIndex = lineIndices[key]; - - // Iterate through each key-value pair in modeConstantValues - modeConstantValues.forEach((configLine) =>{ - // Get the line index for the current key from the record - const lineIndex = lineIndices[configLine.key]; - - // Check if [key, value] to append/remove is found in the file if (lineIndex !== undefined) { - // If the value to insert is not null, update the line with the new value - if (configLine.value !== null) { - lines.splice(lineIndex, 1, `${configLine.key}=${configLine.value}`); + if (value !== null) { + lines.splice(lineIndex, 1, `${key}=${value}`); } else { - // If the value is null, remove the line and update line indices lines.splice(lineIndex, 1); - - // Update line indices for keys that appear after the removed line for (const [k, index] of Object.entries(lineIndices)) { if (index > lineIndex) { lineIndices[k] = index - 1; @@ -197,98 +173,54 @@ function updateConfigFile(path: string, modeConstantValues: ConfigLine[]) { } } } else { - // If it is not found, append the key-value pair to the end of the file content - if (configLine.value !== null) { - addedContent = `${configLine.key}=${configLine.value}\n`; + if (value !== null) { + addedContent = `${key}=${value}\n`; } } - }); + } - // Join the lines back into a single string with line breaks content = lines.join('\n'); - // Append the additional content (if any) to the end of the file content if (addedContent) { content += addedContent; } - // Write the modified content back to the file fs.writeFileSync(path, content); - } - - function updateChainConfig(validiumMode: boolean) { - - const modeConstantValues: ConfigLine[] = [ - { - key: 'compute_overhead_part', - value: validiumMode - ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART - : constants.ROLLUP_COMPUTE_OVERHEAD_PART, - section: null, - }, - { - key: 'pubdata_overhead_part', - value: validiumMode - ? constants.VALIDIUM_PUBDATA_OVERHEAD_PART - : constants.ROLLUP_PUBDATA_OVERHEAD_PART, - section: null, - }, - { - key: 'batch_overhead_l1_gas', - value: validiumMode - ? constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS - : constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, - section: null, - }, - { - key: 'max_pubdata_per_batch', - value: validiumMode - ? constants.VALIDIUM_MAX_PUBDATA_PER_BATCH - : constants.ROLLUP_MAX_PUBDATA_PER_BATCH, - section: null, - }, - { - key: 'l1_batch_commit_data_generator_mode', - value: validiumMode - ? constants.VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE - : constants.ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE, - section: null, - }, - ]; + const modeConstantValues = { + compute_overhead_part: validiumMode + ? constants.VALIDIUM_COMPUTE_OVERHEAD_PART + : constants.ROLLUP_COMPUTE_OVERHEAD_PART, + pubdata_overhead_part: validiumMode + ? constants.VALIDIUM_PUBDATA_OVERHEAD_PART + : constants.ROLLUP_PUBDATA_OVERHEAD_PART, + batch_overhead_l1_gas: validiumMode + ? constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS + : constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, + max_pubdata_per_batch: validiumMode + ? constants.VALIDIUM_MAX_PUBDATA_PER_BATCH + : constants.ROLLUP_MAX_PUBDATA_PER_BATCH, + l1_batch_commit_data_generator_mode: validiumMode + ? constants.VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE + : constants.ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE + }; updateConfigFile(CHAIN_CONFIG_PATH, modeConstantValues); } function updateEthSenderConfig(validiumMode: boolean) { // This constant is used in validium mode and is deleted in rollup mode // In order to pass the existing integration tests - const modeConstantValues: ConfigLine[] = [ - { - key: 'l1_gas_per_pubdata_byte', - value: validiumMode - ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE - : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE, - section: 'en', - }, - ]; + const modeConstantValues = { + l1_gas_per_pubdata_byte: validiumMode + ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE + : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE + }; updateConfigFile(ETH_SENDER_PATH, modeConstantValues); } -function updateExtNodeConfig(validiumMode: boolean) { - const modeConstantValues: ConfigLine[] = [ - { - key: 'l1_batch_commit_data_generator_mode', - value: validiumMode ? 'Validium' : null, - section: 'en', - }, - ]; - updateConfigFile('etc/env/ext-node.toml', modeConstantValues); -} - function updateConfig(validiumMode: boolean) { updateChainConfig(validiumMode); updateEthSenderConfig(validiumMode); - updateExtNodeConfig(validiumMode); config.compileConfig(); let envFileContent = fs.readFileSync(process.env.ENV_FILE!).toString(); envFileContent += `VALIDIUM_MODE=${validiumMode}\n`; From 9ed55e084283e8bea8b8b24c088ccf06821ee378 Mon Sep 17 00:00:00 2001 From: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> Date: Wed, 28 Feb 2024 16:36:06 -0300 Subject: [PATCH 086/106] Delete infrastructure/zk/src/config_constants.ts --- infrastructure/zk/src/config_constants.ts | 36 ----------------------- 1 file changed, 36 deletions(-) delete mode 100644 infrastructure/zk/src/config_constants.ts diff --git a/infrastructure/zk/src/config_constants.ts b/infrastructure/zk/src/config_constants.ts deleted file mode 100644 index 88531b73bc75..000000000000 --- a/infrastructure/zk/src/config_constants.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Include constants to be used on config files. -// Prefix ROLLUP_ or VALIDIUM_ is used to use the right constant depending on the running mode -const VALIDIUM_COMPUTE_OVERHEAD_PART: number = 1.0; -const ROLLUP_COMPUTE_OVERHEAD_PART: number = 0.0; -const VALIDIUM_PUBDATA_OVERHEAD_PART: number = 0.0; -const ROLLUP_PUBDATA_OVERHEAD_PART: number = 1.0; -const VALIDIUM_BATCH_OVERHEAD_L1_GAS: number = 1000000; -const ROLLUP_BATCH_OVERHEAD_L1_GAS: number = 800000; -const VALIDIUM_MAX_PUBDATA_PER_BATCH: number = 1000000000000; -const ROLLUP_MAX_PUBDATA_PER_BATCH: number = 100000; -const VALIDIUM_L1_GAS_PER_PUBDATA_BYTE: number = 0; -const ROLLUP_L1_GAS_PER_PUBDATA_BYTE: number = 17; -const VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Validium"'; -const ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE: string = '"Rollup"'; - -//Define config file's path that are updated depending on the running mode (Validium or Rollup) -export const CHAIN_CONFIG_PATH = 'etc/env/base/chain.toml'; -export const ETH_SENDER_PATH = 'etc/env/base/eth_sender.toml'; - -export function getEthSenderConfigConstants(validiumMode: boolean): Record { - return { - l1_gas_per_pubdata_byte: validiumMode ? VALIDIUM_L1_GAS_PER_PUBDATA_BYTE : ROLLUP_L1_GAS_PER_PUBDATA_BYTE - }; -} - -export function getChainConfigConstants(validiumMode: boolean): Record { - return { - compute_overhead_part: validiumMode ? VALIDIUM_COMPUTE_OVERHEAD_PART : ROLLUP_COMPUTE_OVERHEAD_PART, - pubdata_overhead_part: validiumMode ? VALIDIUM_PUBDATA_OVERHEAD_PART : ROLLUP_PUBDATA_OVERHEAD_PART, - batch_overhead_l1_gas: validiumMode ? VALIDIUM_BATCH_OVERHEAD_L1_GAS : ROLLUP_BATCH_OVERHEAD_L1_GAS, - max_pubdata_per_batch: validiumMode ? VALIDIUM_MAX_PUBDATA_PER_BATCH : ROLLUP_MAX_PUBDATA_PER_BATCH, - l1_batch_commit_data_generator_mode: validiumMode - ? VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE - : ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE - }; -} From daf7e4d502fea47abc804b0abc88bc5b3fe96bce Mon Sep 17 00:00:00 2001 From: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> Date: Wed, 28 Feb 2024 16:36:41 -0300 Subject: [PATCH 087/106] Update config.ts --- infrastructure/zk/src/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/infrastructure/zk/src/config.ts b/infrastructure/zk/src/config.ts index 2541055bb8c0..0496f1e46d35 100644 --- a/infrastructure/zk/src/config.ts +++ b/infrastructure/zk/src/config.ts @@ -1,7 +1,6 @@ import { Command } from 'commander'; import * as toml from '@iarna/toml'; import * as fs from 'fs'; -import * as config_constants from './config_constants'; import deepExtend from 'deep-extend'; function loadConfigFile(path: string) { From e1e01dd55a9a86ebabc06e0b1737d0c2cccab83f Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 16:41:31 -0300 Subject: [PATCH 088/106] Init system using DeploymentMode enum --- infrastructure/zk/src/contract.ts | 25 ++++- infrastructure/zk/src/hyperchain_wizard.ts | 5 +- infrastructure/zk/src/init.ts | 112 +++++++++++---------- 3 files changed, 84 insertions(+), 58 deletions(-) diff --git a/infrastructure/zk/src/contract.ts b/infrastructure/zk/src/contract.ts index fec4eba4963c..9ea4257838cc 100644 --- a/infrastructure/zk/src/contract.ts +++ b/infrastructure/zk/src/contract.ts @@ -143,13 +143,30 @@ export async function deployL1(args: any[]) { fs.writeFileSync('deployed_contracts.log', updatedContracts); } -export async function redeployL1(args: any[]) { - await deployL1(args); +export enum DeploymentMode { + Rollup = 0, + Validium = 1 +} + +export async function redeployL1(args: any[], deploymentMode: DeploymentMode) { + if (deploymentMode == DeploymentMode.Validium) { + await deployL1([...args, '--validium-mode']); + } else if (deploymentMode == DeploymentMode.Rollup) { + await deployL1(args); + } else { + throw new Error('Invalid deployment mode'); + } await verifyL1Contracts(); } -export async function deployVerifier(args: any[]) { - await deployL1([...args, '--only-verifier']); +export async function deployVerifier(args: any[], deploymentMode: DeploymentMode) { + if (deploymentMode == DeploymentMode.Validium) { + await deployL1([...args, '--only-verifier', '--validium-mode']); + } else if (deploymentMode == DeploymentMode.Rollup) { + await deployL1([...args, '--only-verifier']); + } else { + throw new Error('Invalid deployment mode'); + } } export const command = new Command('contract').description('contract management'); diff --git a/infrastructure/zk/src/hyperchain_wizard.ts b/infrastructure/zk/src/hyperchain_wizard.ts index d614db797ce1..30cea87c7ef2 100644 --- a/infrastructure/zk/src/hyperchain_wizard.ts +++ b/infrastructure/zk/src/hyperchain_wizard.ts @@ -13,6 +13,7 @@ import fetch from 'node-fetch'; import { up } from './up'; import * as Handlebars from 'handlebars'; import { ProverType, setupProver } from './prover_setup'; +import { DeploymentMode } from './contract'; const title = chalk.blueBright; const warning = chalk.yellowBright; @@ -67,7 +68,7 @@ async function initHyperchain() { args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] }, deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey, '--owner-address', governorAdrress], - validiumMode: false + deploymentMode: DeploymentMode.Rollup }; await init(initArgs); @@ -813,7 +814,7 @@ async function configDemoHyperchain(cmd: Command) { args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] }, deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey], - validiumMode: false + deploymentMode: DeploymentMode.Rollup }; if (!cmd.skipEnvSetup) { diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index e719d71d204e..4679530a93e0 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -31,11 +31,13 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { governorPrivateKeyArgs, deployerPrivateKeyArgs, deployerL2ContractInput, - validiumMode + deploymentMode } = initArgs; - await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - await announced('Updating mode configuration', updateConfig(validiumMode)); + await announced( + `Initializing in ${deploymentMode == contract.DeploymentMode.Validium ? 'Validium mode' : 'Roll-up mode'}` + ); + await announced('Updating mode configuration', updateConfig(deploymentMode)); if (!process.env.CI && !skipEnvSetup) { await announced('Pulling images', docker.pull()); await announced('Checking environment', checkEnv()); @@ -56,13 +58,10 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { if (testTokens.deploy) { await announced('Deploying localhost ERC20 tokens', run.deployERC20('dev', '', '', '', testTokens.args)); } - await announced('Deploying L1 verifier', contract.deployVerifier(deployerPrivateKeyArgs)); + await announced('Deploying L1 verifier', contract.deployVerifier(deployerPrivateKeyArgs, deploymentMode)); await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromSources()); - await announced( - 'Deploying L1 contracts', - contract.redeployL1([...deployerPrivateKeyArgs, ...additionalArgumentsForRedeployingL1(validiumMode)]) - ); + await announced('Deploying L1 contracts', contract.redeployL1(deployerPrivateKeyArgs, deploymentMode)); await announced('Initializing validator', contract.initializeValidator(governorPrivateKeyArgs)); await announced( 'Deploying L2 contracts', @@ -81,9 +80,11 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { // A smaller version of `init` that "resets" the localhost environment, for which `init` was already called before. // It does less and runs much faster. -export async function reinit(validiumMode: boolean) { - await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - await announced('Updating mode configuration', updateConfig(validiumMode)); +export async function reinit(deploymentMode: contract.DeploymentMode) { + await announced( + `Initializing in ${deploymentMode == contract.DeploymentMode.Validium ? 'Validium mode' : 'Roll-up mode'}` + ); + await announced('Updating mode configuration', updateConfig(deploymentMode)); await announced('Setting up containers', up()); await announced('Compiling JS packages', run.yarn()); await announced('Compile l2 contracts', compiler.compileAll()); @@ -92,10 +93,10 @@ export async function reinit(validiumMode: boolean) { await announced('Clean rocksdb', clean('db')); await announced('Clean backups', clean('backups')); await announced('Building contracts', contract.build()); - await announced('Deploying L1 verifier', contract.deployVerifier([])); + await announced('Deploying L1 verifier', contract.deployVerifier([], deploymentMode)); await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromSources()); - await announced('Deploying L1 contracts', contract.redeployL1(additionalArgumentsForRedeployingL1(validiumMode))); + await announced('Deploying L1 contracts', contract.redeployL1([], deploymentMode)); await announced('Deploying L2 contracts', contract.deployL2([], true, true)); await announced('Initializing L2 WETH token', contract.initializeWethToken()); await announced('Initializing governance', contract.initializeGovernance()); @@ -103,17 +104,19 @@ export async function reinit(validiumMode: boolean) { } // A lightweight version of `init` that sets up local databases, generates genesis and deploys precompiled contracts -export async function lightweightInit(validiumMode: boolean) { - await announced(`Initializing in ${validiumMode ? 'Validium mode' : 'Roll-up mode'}`); - await announced('Updating mode configuration', updateConfig(validiumMode)); +export async function lightweightInit(deploymentMode: contract.DeploymentMode) { + await announced( + `Initializing in ${deploymentMode == contract.DeploymentMode.Validium ? 'Validium mode' : 'Roll-up mode'}` + ); + await announced('Updating mode configuration', updateConfig(deploymentMode)); await announced(`Setting up containers`, up()); await announced('Clean rocksdb', clean('db')); await announced('Clean backups', clean('backups')); - await announced('Deploying L1 verifier', contract.deployVerifier([])); + await announced('Deploying L1 verifier', contract.deployVerifier([], deploymentMode)); await announced('Reloading env', env.reload()); await announced('Running server genesis setup', server.genesisFromBinary()); await announced('Deploying localhost ERC20 tokens', run.deployERC20('dev', '', '', '', [])); - await announced('Deploying L1 contracts', contract.redeployL1(additionalArgumentsForRedeployingL1(validiumMode))); + await announced('Deploying L1 contracts', contract.redeployL1([], deploymentMode)); await announced('Initializing validator', contract.initializeValidator()); await announced('Deploying L2 contracts', contract.deployL2([], true, false)); await announced('Initializing governance', contract.initializeGovernance()); @@ -187,40 +190,44 @@ function updateConfigFile(path: string, modeConstantValues: Record; + if (deploymentMode == contract.DeploymentMode.Validium) { + modeConstantValues = { + compute_overhead_part: constants.VALIDIUM_COMPUTE_OVERHEAD_PART, + pubdata_overhead_part: constants.VALIDIUM_PUBDATA_OVERHEAD_PART, + batch_overhead_l1_gas: constants.VALIDIUM_BATCH_OVERHEAD_L1_GAS, + max_pubdata_per_batch: constants.VALIDIUM_MAX_PUBDATA_PER_BATCH, + l1_batch_commit_data_generator_mode: constants.VALIDIUM_L1_BATCH_COMMIT_DATA_GENERATOR_MODE + }; + } else if (deploymentMode == contract.DeploymentMode.Rollup) { + modeConstantValues = { + compute_overhead_part: constants.ROLLUP_COMPUTE_OVERHEAD_PART, + pubdata_overhead_part: constants.ROLLUP_PUBDATA_OVERHEAD_PART, + batch_overhead_l1_gas: constants.ROLLUP_BATCH_OVERHEAD_L1_GAS, + max_pubdata_per_batch: constants.ROLLUP_MAX_PUBDATA_PER_BATCH, + l1_batch_commit_data_generator_mode: constants.ROLLUP_L1_BATCH_COMMIT_DATA_GENERATOR_MODE + }; + } else { + throw new Error('Invalid deployment mode'); + } updateConfigFile(CHAIN_CONFIG_PATH, modeConstantValues); } -function updateEthSenderConfig(validiumMode: boolean) { +function updateEthSenderConfig(deploymentMode: contract.DeploymentMode) { // This constant is used in validium mode and is deleted in rollup mode // In order to pass the existing integration tests const modeConstantValues = { - l1_gas_per_pubdata_byte: validiumMode - ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE - : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE + l1_gas_per_pubdata_byte: + deploymentMode == contract.DeploymentMode.Validium + ? constants.VALIDIUM_L1_GAS_PER_PUBDATA_BYTE + : constants.ROLLUP_L1_GAS_PER_PUBDATA_BYTE }; updateConfigFile(ETH_SENDER_PATH, modeConstantValues); } -function updateConfig(validiumMode: boolean) { - updateChainConfig(validiumMode); - updateEthSenderConfig(validiumMode); +function updateConfig(deploymentMode: contract.DeploymentMode) { + updateChainConfig(deploymentMode); + updateEthSenderConfig(deploymentMode); config.compileConfig(); } @@ -237,10 +244,6 @@ async function checkEnv() { } } -function additionalArgumentsForRedeployingL1(validium: boolean) { - return validium ? ['--validium-mode'] : []; -} - export interface InitArgs { skipSubmodulesCheckout: boolean; skipEnvSetup: boolean; @@ -255,7 +258,7 @@ export interface InitArgs { deploy: boolean; args: any[]; }; - validiumMode: boolean; + deploymentMode: contract.DeploymentMode; } const DEFAULT_ARGS: InitArgs = { @@ -265,7 +268,7 @@ const DEFAULT_ARGS: InitArgs = { deployerPrivateKeyArgs: [], deployerL2ContractInput: { args: [], includePaymaster: true, includeL2WETH: true }, testTokens: { deploy: true, args: [] }, - validiumMode: false + deploymentMode: contract.DeploymentMode.Rollup }; export const initCommand = new Command('init') @@ -281,17 +284,22 @@ export const initCommand = new Command('init') deployerL2ContractInput: { args: [], includePaymaster: true, includeL2WETH: true }, testTokens: { deploy: true, args: [] }, deployerPrivateKeyArgs: [], - validiumMode: cmd.validiumMode !== undefined ? cmd.validiumMode : false + deploymentMode: + cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium }; await init(initArgs); }); export const reinitCommand = new Command('reinit') .description('"reinitializes" network. Runs faster than `init`, but requires `init` to be executed prior') .action(async (cmd: Command) => { - await reinit(cmd.validiumMode); + let deploymentMode = + cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium; + await reinit(deploymentMode); }); export const lightweightInitCommand = new Command('lightweight-init') .description('perform lightweight zksync network initialization for development') .action(async (cmd: Command) => { - await lightweightInit(cmd.validiumMode); + let deploymentMode = + cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium; + await lightweightInit(deploymentMode); }); From 1adeb3a9a6ac8e505c377e09f2bb7ef6a4d3a12e Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 16:44:07 -0300 Subject: [PATCH 089/106] Fix lightweight-init and reinit cmds --- infrastructure/zk/src/init.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index 4679530a93e0..d838aef482e1 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -291,6 +291,7 @@ export const initCommand = new Command('init') }); export const reinitCommand = new Command('reinit') .description('"reinitializes" network. Runs faster than `init`, but requires `init` to be executed prior') + .option('--validium-mode') .action(async (cmd: Command) => { let deploymentMode = cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium; @@ -298,6 +299,7 @@ export const reinitCommand = new Command('reinit') }); export const lightweightInitCommand = new Command('lightweight-init') .description('perform lightweight zksync network initialization for development') + .option('--validium-mode') .action(async (cmd: Command) => { let deploymentMode = cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium; From f89ebda474c7e7ceb327ac705a95e16293ccabd1 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 16:57:53 -0300 Subject: [PATCH 090/106] Fix hyperchain_wizard --- infrastructure/zk/src/hyperchain_wizard.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/infrastructure/zk/src/hyperchain_wizard.ts b/infrastructure/zk/src/hyperchain_wizard.ts index 30cea87c7ef2..85820b822df9 100644 --- a/infrastructure/zk/src/hyperchain_wizard.ts +++ b/infrastructure/zk/src/hyperchain_wizard.ts @@ -45,7 +45,7 @@ export interface BasePromptOptions { } // An init command that allows configuring and spinning up a new hyperchain network. -async function initHyperchain() { +async function initHyperchain(deploymentMode: DeploymentMode) { await announced('Initializing hyperchain creation', setupConfiguration()); const deployerPrivateKey = process.env.DEPLOYER_PRIVATE_KEY; @@ -68,7 +68,7 @@ async function initHyperchain() { args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] }, deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey, '--owner-address', governorAdrress], - deploymentMode: DeploymentMode.Rollup + deploymentMode }; await init(initArgs); @@ -814,7 +814,7 @@ async function configDemoHyperchain(cmd: Command) { args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] }, deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey], - deploymentMode: DeploymentMode.Rollup + deploymentMode: cmd.validiumMode !== undefined ? DeploymentMode.Rollup : DeploymentMode.Validium }; if (!cmd.skipEnvSetup) { @@ -869,7 +869,11 @@ export const initHyperchainCommand = new Command('stack') initHyperchainCommand .command('init') .description('Wizard for hyperchain creation/configuration') - .action(initHyperchain); + .option('--validium-mode') + .action(async (cmd: Command) => { + let deploymentMode = cmd.validiumMode !== undefined ? DeploymentMode.Rollup : DeploymentMode.Validium; + await initHyperchain(deploymentMode); + }); initHyperchainCommand .command('docker-setup') .option('--custom-docker-org ', 'Custom organization name for the docker images') @@ -883,5 +887,6 @@ initHyperchainCommand .command('demo') .option('--prover ', 'Add a cpu or gpu prover to the hyperchain') .option('--skip-env-setup', 'Run env setup automatically (pull docker containers, etc)') + .option('--validium-mode') .description('Spin up a demo hyperchain with default settings for testing purposes') .action(configDemoHyperchain); From 2a9cf8fefbfd2bb3b3aabbe3e1e25ab1f9228107 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 17:21:06 -0300 Subject: [PATCH 091/106] Fix conditional --- infrastructure/zk/src/hyperchain_wizard.ts | 4 ++-- infrastructure/zk/src/init.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/infrastructure/zk/src/hyperchain_wizard.ts b/infrastructure/zk/src/hyperchain_wizard.ts index 85820b822df9..773e47085b5f 100644 --- a/infrastructure/zk/src/hyperchain_wizard.ts +++ b/infrastructure/zk/src/hyperchain_wizard.ts @@ -814,7 +814,7 @@ async function configDemoHyperchain(cmd: Command) { args: ['--private-key', deployerPrivateKey, '--envFile', process.env.CHAIN_ETH_NETWORK!] }, deployerPrivateKeyArgs: ['--private-key', deployerPrivateKey], - deploymentMode: cmd.validiumMode !== undefined ? DeploymentMode.Rollup : DeploymentMode.Validium + deploymentMode: cmd.validiumMode !== undefined ? DeploymentMode.Validium : DeploymentMode.Rollup }; if (!cmd.skipEnvSetup) { @@ -871,7 +871,7 @@ initHyperchainCommand .description('Wizard for hyperchain creation/configuration') .option('--validium-mode') .action(async (cmd: Command) => { - let deploymentMode = cmd.validiumMode !== undefined ? DeploymentMode.Rollup : DeploymentMode.Validium; + let deploymentMode = cmd.validiumMode !== undefined ? DeploymentMode.Validium : DeploymentMode.Rollup; await initHyperchain(deploymentMode); }); initHyperchainCommand diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index d838aef482e1..786e12c2c3bc 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -285,7 +285,7 @@ export const initCommand = new Command('init') testTokens: { deploy: true, args: [] }, deployerPrivateKeyArgs: [], deploymentMode: - cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium + cmd.validiumMode !== undefined ? contract.DeploymentMode.Validium : contract.DeploymentMode.Rollup }; await init(initArgs); }); @@ -294,7 +294,7 @@ export const reinitCommand = new Command('reinit') .option('--validium-mode') .action(async (cmd: Command) => { let deploymentMode = - cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium; + cmd.validiumMode !== undefined ? contract.DeploymentMode.Validium : contract.DeploymentMode.Rollup; await reinit(deploymentMode); }); export const lightweightInitCommand = new Command('lightweight-init') @@ -302,6 +302,6 @@ export const lightweightInitCommand = new Command('lightweight-init') .option('--validium-mode') .action(async (cmd: Command) => { let deploymentMode = - cmd.validiumMode !== undefined ? contract.DeploymentMode.Rollup : contract.DeploymentMode.Validium; + cmd.validiumMode !== undefined ? contract.DeploymentMode.Validium : contract.DeploymentMode.Rollup; await lightweightInit(deploymentMode); }); From 3805f90d3b53e03479d78b6a78c39c55f88411b3 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 18:31:20 -0300 Subject: [PATCH 092/106] Fix merge --- infrastructure/zk/src/init.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index ea451fac5f09..091ad685cc1b 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -34,7 +34,6 @@ export async function init(initArgs: InitArgs = DEFAULT_ARGS) { await announced( `Initializing in ${deploymentMode == contract.DeploymentMode.Validium ? 'Validium mode' : 'Roll-up mode'}` ); - await announced('Updating mode configuration', updateConfig(deploymentMode)); if (!process.env.CI && !skipEnvSetup) { await announced('Pulling images', docker.pull()); await announced('Checking environment', checkEnv()); @@ -81,7 +80,6 @@ export async function reinit(deploymentMode: contract.DeploymentMode) { await announced( `Initializing in ${deploymentMode == contract.DeploymentMode.Validium ? 'Validium mode' : 'Roll-up mode'}` ); - await announced('Updating mode configuration', updateConfig(deploymentMode)); await announced('Setting up containers', up()); await announced('Compiling JS packages', run.yarn()); await announced('Compile l2 contracts', compiler.compileAll()); @@ -105,7 +103,6 @@ export async function lightweightInit(deploymentMode: contract.DeploymentMode) { await announced( `Initializing in ${deploymentMode == contract.DeploymentMode.Validium ? 'Validium mode' : 'Roll-up mode'}` ); - await announced('Updating mode configuration', updateConfig(deploymentMode)); await announced(`Setting up containers`, up()); await announced('Clean rocksdb', clean('db')); await announced('Clean backups', clean('backups')); From f2e90fc0c6e1d2491cff57a27a48d5b3ffac9d81 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 19:59:57 -0300 Subject: [PATCH 093/106] Fix compilation error in tests (because of a merge) --- core/lib/zksync_core/src/eth_sender/tests_helpers.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/lib/zksync_core/src/eth_sender/tests_helpers.rs b/core/lib/zksync_core/src/eth_sender/tests_helpers.rs index f168fd702480..a33579f83cef 100644 --- a/core/lib/zksync_core/src/eth_sender/tests_helpers.rs +++ b/core/lib/zksync_core/src/eth_sender/tests_helpers.rs @@ -114,8 +114,9 @@ impl EthSenderTester { Address::random(), contracts_config.l1_multicall3_addr, Address::random(), - 0, - ); + Default::default(), + ) + .await; let manager = EthTxManager::new( eth_sender_config.sender, From 9b37ccde37257330d58866be5ed4b4e9757a3723 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Wed, 28 Feb 2024 20:31:34 -0300 Subject: [PATCH 094/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index bf0dbcca08ab..6804b2374ce2 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit bf0dbcca08abd6a64ec4f09c7ccbfb6fe5bf0e9e +Subproject commit 6804b2374ce23a8f85f4e2d4ec96219c6aad6653 From 5783c1bd41e01d8e72f11d9ffc381ad6713720de Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 09:30:27 -0300 Subject: [PATCH 095/106] Remove unused imports --- infrastructure/zk/src/init.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/infrastructure/zk/src/init.ts b/infrastructure/zk/src/init.ts index d7d034c0ec69..5df56b257297 100644 --- a/infrastructure/zk/src/init.ts +++ b/infrastructure/zk/src/init.ts @@ -4,7 +4,6 @@ import * as utils from './utils'; import { clean } from './clean'; import * as compiler from './compiler'; -import * as config from './config'; import * as contract from './contract'; import * as db from './database'; import * as docker from './docker'; @@ -13,8 +12,6 @@ import * as run from './run'; import * as server from './server'; import { up } from './up'; -import * as fs from 'fs'; - const entry = chalk.bold.yellow; const announce = chalk.yellow; const success = chalk.green; From ea433efa89deac00ffc8cbb133cdcbb370839375 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 09:31:40 -0300 Subject: [PATCH 096/106] Update contracts submodule commit --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index a99c79683c18..6804b2374ce2 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit a99c79683c18cbda8f23b1310255d3710ffe1697 +Subproject commit 6804b2374ce23a8f85f4e2d4ec96219c6aad6653 From baa1083284a0b0721de4fc103249904cb50623e7 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 09:59:00 -0300 Subject: [PATCH 097/106] Revert "Add executor_contract getter" This reverts commit 3a9e133c6fea46af0331079d072e678a6739a54e. --- core/lib/contracts/src/lib.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/core/lib/contracts/src/lib.rs b/core/lib/contracts/src/lib.rs index 3ba46654a793..f6bfd9c1e4a3 100644 --- a/core/lib/contracts/src/lib.rs +++ b/core/lib/contracts/src/lib.rs @@ -39,8 +39,6 @@ const LOADNEXT_CONTRACT_FILE: &str = "etc/contracts-test-data/artifacts-zk/contracts/loadnext/loadnext_contract.sol/LoadnextContract.json"; const LOADNEXT_SIMPLE_CONTRACT_FILE: &str = "etc/contracts-test-data/artifacts-zk/contracts/loadnext/loadnext_contract.sol/Foo.json"; -const EXECUTOR_CONTRACT_FILE: &str = - "contracts/l1-contracts/artifacts/cache/solpp-generated-contracts/zksync/facets/Executor.sol/ExecutorFacet.json"; fn read_file_to_json_value(path: impl AsRef) -> serde_json::Value { let zksync_home = std::env::var("ZKSYNC_HOME").unwrap_or_else(|_| ".".into()); @@ -93,10 +91,6 @@ pub fn verifier_contract() -> Contract { load_contract(VERIFIER_CONTRACT_FILE) } -pub fn executor_contract() -> Contract { - load_contract(EXECUTOR_CONTRACT_FILE) -} - #[derive(Debug, Clone)] pub struct TestContract { /// Contract bytecode to be used for sending deploy transaction. From 06752d657cb0c053091a3ee19a82007098be8328 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 09:59:31 -0300 Subject: [PATCH 098/106] Fix method name --- core/lib/zksync_core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index f2f2626925b6..ef91fe5b7058 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -631,7 +631,7 @@ pub async fn initialize_components( } }; - let args = CallFunctionArgs::new("getPubdataPriceMode", ()).for_contract( + let args = CallFunctionArgs::new("getPubdataPricingMode", ()).for_contract( contracts_config.executor_facet_addr, zksync_contracts::executor_contract(), ); From d6c1c202796137325ac6093a706cde28a130ec5b Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 10:03:18 -0300 Subject: [PATCH 099/106] Improve assert comment --- core/lib/zksync_core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index ef91fe5b7058..ddfb6679a7d2 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -644,7 +644,7 @@ pub async fn initialize_components( assert_eq!( current_commitment_mode, state_keeper_config.l1_batch_commit_data_generator_mode, - "The selected L1BatchCommitDataGeneratorMode ({:?}) does not match the existing commitment mode ({:?})", + "The selected L1BatchCommitDataGeneratorMode ({:?}) does not match the commitment mode used on L1 contract ({:?})", state_keeper_config.l1_batch_commit_data_generator_mode, current_commitment_mode ); From 538b64f0bb1835a5c9a6c2f896f5ff1beedfb55d Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 10:27:26 -0300 Subject: [PATCH 100/106] Fix call to getPubdataPricingMode method --- core/lib/zksync_core/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index ddfb6679a7d2..910c25daf193 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -632,8 +632,8 @@ pub async fn initialize_components( }; let args = CallFunctionArgs::new("getPubdataPricingMode", ()).for_contract( - contracts_config.executor_facet_addr, - zksync_contracts::executor_contract(), + contracts_config.diamond_proxy_addr, + zksync_contracts::zksync_contract(), ); let current_commitment_mode_eth_response = eth_client.call_contract_function(args).await?; From d58e1acd5b3d4d8393fa8395f038d8ec731f10ab Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 18:04:37 -0300 Subject: [PATCH 101/106] Refactor --- core/lib/zksync_core/src/lib.rs | 56 ++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 1b7a2859ab2b..af30ebde7958 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -30,7 +30,7 @@ use zksync_contracts::{governance_contract, BaseSystemContracts}; use zksync_dal::{healthcheck::ConnectionPoolHealthCheck, ConnectionPool}; use zksync_eth_client::{ clients::{PKSigningClient, QueryClient}, - CallFunctionArgs, EthInterface, + CallFunctionArgs, Error as EthClientError, EthInterface, }; use zksync_health_check::{AppHealthCheck, HealthStatus, ReactiveHealthCheck}; use zksync_object_store::{ObjectStore, ObjectStoreFactory}; @@ -44,7 +44,10 @@ use zksync_types::{ }, protocol_version::{L1VerifierConfig, VerifierParams}, system_contracts::get_system_smart_contracts, - web3::contract::tokens::Detokenize, + web3::{ + contract::{tokens::Detokenize, Error as Web3ContractError}, + ethabi, + }, L2ChainId, PackedEthSignature, ProtocolVersionId, }; @@ -298,6 +301,17 @@ impl FromStr for Components { } } +async fn get_pubdata_pricing_mode( + contracts_config: &ContractsConfig, + eth_client: &impl EthInterface, +) -> Result, EthClientError> { + let args = CallFunctionArgs::new("getPubdataPricingMode", ()).for_contract( + contracts_config.diamond_proxy_addr, + zksync_contracts::zksync_contract(), + ); + eth_client.call_contract_function(args).await +} + pub async fn initialize_components( configs: &TempConfigStore, components: Vec, @@ -637,8 +651,26 @@ pub async fn initialize_components( .state_keeper_config .clone() .context("state_keeper_config")?; + + let selected_l1_batch_commit_data_generator_mode = state_keeper_config + .l1_batch_commit_data_generator_mode + .clone(); + let l1_contract_pubdata_pricing_mode = + get_pubdata_pricing_mode(&contracts_config, ð_client).await?; + let l1_contract_batch_commitment_mode = + L1BatchCommitDataGeneratorMode::from_tokens(l1_contract_pubdata_pricing_mode)?; + + // contracts mode == server mode + assert_eq!( + l1_contract_batch_commitment_mode, + selected_l1_batch_commit_data_generator_mode, + "The selected L1BatchCommitDataGeneratorMode ({:?}) does not match the commitment mode used on L1 contract ({:?})", + selected_l1_batch_commit_data_generator_mode, + l1_contract_batch_commitment_mode + ); + let l1_batch_commit_data_generator: Arc = - match state_keeper_config.l1_batch_commit_data_generator_mode { + match selected_l1_batch_commit_data_generator_mode { L1BatchCommitDataGeneratorMode::Rollup => { Arc::new(RollupModeL1BatchCommitDataGenerator {}) } @@ -647,24 +679,6 @@ pub async fn initialize_components( } }; - let args = CallFunctionArgs::new("getPubdataPricingMode", ()).for_contract( - contracts_config.diamond_proxy_addr, - zksync_contracts::zksync_contract(), - ); - let current_commitment_mode_eth_response = eth_client.call_contract_function(args).await?; - - let current_commitment_mode = - L1BatchCommitDataGeneratorMode::from_tokens(current_commitment_mode_eth_response)?; - - // contracts mode == server mode - assert_eq!( - current_commitment_mode, - state_keeper_config.l1_batch_commit_data_generator_mode, - "The selected L1BatchCommitDataGeneratorMode ({:?}) does not match the commitment mode used on L1 contract ({:?})", - state_keeper_config.l1_batch_commit_data_generator_mode, - current_commitment_mode - ); - let eth_tx_aggregator_actor = EthTxAggregator::new( eth_sender.sender.clone(), Aggregator::new( From 000775aa01151aeee1ffdd24c98a167d4c15fc90 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 18:05:25 -0300 Subject: [PATCH 102/106] Remove unused import --- core/lib/zksync_core/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index af30ebde7958..8393e85f8b2c 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -44,10 +44,7 @@ use zksync_types::{ }, protocol_version::{L1VerifierConfig, VerifierParams}, system_contracts::get_system_smart_contracts, - web3::{ - contract::{tokens::Detokenize, Error as Web3ContractError}, - ethabi, - }, + web3::{contract::tokens::Detokenize, ethabi}, L2ChainId, PackedEthSignature, ProtocolVersionId, }; From 9586ecc3e45dbe53232edbe55efcf3754afe3c67 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 18:39:31 -0300 Subject: [PATCH 103/106] Handle special case where these changes are merged before the contracts are deployed on testnet/mainnet --- core/lib/zksync_core/src/lib.rs | 57 +++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index 8393e85f8b2c..ba4eecfd161a 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -298,6 +298,39 @@ impl FromStr for Components { } } +async fn ensure_l1_batch_commit_data_generation_mode( + state_keeper_config: &StateKeeperConfig, + contracts_config: &ContractsConfig, + eth_client: &impl EthInterface, +) -> anyhow::Result<()> { + let selected_l1_batch_commit_data_generator_mode = state_keeper_config + .l1_batch_commit_data_generator_mode + .clone(); + match get_pubdata_pricing_mode(&contracts_config, eth_client).await { + // Getters contract support getPubdataPricingMode method + Ok(l1_contract_pubdata_pricing_mode) => { + let l1_contract_batch_commitment_mode = + L1BatchCommitDataGeneratorMode::from_tokens(l1_contract_pubdata_pricing_mode)?; + + // contracts mode == server mode + anyhow::ensure!( + l1_contract_batch_commitment_mode == selected_l1_batch_commit_data_generator_mode, + "The selected L1BatchCommitDataGeneratorMode ({:?}) does not match the commitment mode used on L1 contract ({:?})", + selected_l1_batch_commit_data_generator_mode, + l1_contract_batch_commitment_mode + ); + + Ok(()) + } + // Getters contract does not support getPubdataPricingMode method + Err(EthClientError::Contract(_)) => { + tracing::warn!("Getters contract does not support getPubdataPricingMode method"); + Ok(()) + } + Err(err) => anyhow::bail!(err), + } +} + async fn get_pubdata_pricing_mode( contracts_config: &ContractsConfig, eth_client: &impl EthInterface, @@ -649,25 +682,15 @@ pub async fn initialize_components( .clone() .context("state_keeper_config")?; - let selected_l1_batch_commit_data_generator_mode = state_keeper_config - .l1_batch_commit_data_generator_mode - .clone(); - let l1_contract_pubdata_pricing_mode = - get_pubdata_pricing_mode(&contracts_config, ð_client).await?; - let l1_contract_batch_commitment_mode = - L1BatchCommitDataGeneratorMode::from_tokens(l1_contract_pubdata_pricing_mode)?; - - // contracts mode == server mode - assert_eq!( - l1_contract_batch_commitment_mode, - selected_l1_batch_commit_data_generator_mode, - "The selected L1BatchCommitDataGeneratorMode ({:?}) does not match the commitment mode used on L1 contract ({:?})", - selected_l1_batch_commit_data_generator_mode, - l1_contract_batch_commitment_mode - ); + ensure_l1_batch_commit_data_generation_mode( + &state_keeper_config, + &contracts_config, + ð_client, + ) + .await?; let l1_batch_commit_data_generator: Arc = - match selected_l1_batch_commit_data_generator_mode { + match state_keeper_config.l1_batch_commit_data_generator_mode { L1BatchCommitDataGeneratorMode::Rollup => { Arc::new(RollupModeL1BatchCommitDataGenerator {}) } From c241c78b0b85599120de8df2440d8cfcf2e230ac Mon Sep 17 00:00:00 2001 From: ilitteri Date: Thu, 29 Feb 2024 19:01:32 -0300 Subject: [PATCH 104/106] Update era.dic --- checks-config/era.dic | 2 ++ 1 file changed, 2 insertions(+) diff --git a/checks-config/era.dic b/checks-config/era.dic index 3f8eb807b6e8..e0f22785b4ef 100644 --- a/checks-config/era.dic +++ b/checks-config/era.dic @@ -906,3 +906,5 @@ balancer lookups stateful DeployRequest +getPubdataPricingMode +Uint From d7789fce058ae90f1c78ecbcaa6dedbf527ac90f Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 1 Mar 2024 11:56:49 -0300 Subject: [PATCH 105/106] Fix comment --- core/lib/config/src/configs/chain.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index bcefc396e37f..0a8ce1b9823a 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -5,10 +5,9 @@ use zksync_basic_types::{ network::Network, web3::{ contract::{tokens::Detokenize, Error as Web3ContractError}, - error::Error as Web3ApiError, ethabi, }, - Address, Bytes, L2ChainId, U256, + Address, L2ChainId, U256, }; #[derive(Debug, Deserialize, Clone, PartialEq)] @@ -62,14 +61,12 @@ pub enum L1BatchCommitDataGeneratorMode { // The cases are extracted from the `PubdataPricingMode` enum in the L1 contracts, // And knowing that, in Ethereum, the response is the index of the enum case. -// If the Uint token is 0 I want the Rollup case, -// If the Uint token is 1 I want the Validium case, -// Else, an error. +// 0 corresponds to Rollup case, +// 1 corresponds to Validium case, +// Other values are incorrect. impl Detokenize for L1BatchCommitDataGeneratorMode { fn from_tokens(tokens: Vec) -> Result { - let error = Err(Web3ContractError::Api(Web3ApiError::Decoder( - "L1BatchCommitDataGeneratorMode::from_tokens".to_string(), - ))); + let error = Err(Web3ContractError::Abi(ethabi::Error::InvalidData)); match tokens.as_slice() { [ethabi::Token::Uint(enum_value)] => { if enum_value == &U256::zero() { From ac7f5fb38244e13693479bad94f9ac762048a69b Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 1 Mar 2024 13:48:04 -0300 Subject: [PATCH 106/106] Address nits --- core/lib/config/src/configs/chain.rs | 13 +++++++++---- core/lib/zksync_core/src/lib.rs | 5 ++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/core/lib/config/src/configs/chain.rs b/core/lib/config/src/configs/chain.rs index 0a8ce1b9823a..e63a19e51c72 100644 --- a/core/lib/config/src/configs/chain.rs +++ b/core/lib/config/src/configs/chain.rs @@ -5,7 +5,7 @@ use zksync_basic_types::{ network::Network, web3::{ contract::{tokens::Detokenize, Error as Web3ContractError}, - ethabi, + ethabi, Error as Web3ApiError, }, Address, L2ChainId, U256, }; @@ -66,7 +66,12 @@ pub enum L1BatchCommitDataGeneratorMode { // Other values are incorrect. impl Detokenize for L1BatchCommitDataGeneratorMode { fn from_tokens(tokens: Vec) -> Result { - let error = Err(Web3ContractError::Abi(ethabi::Error::InvalidData)); + fn error(tokens: &[ethabi::Token]) -> Web3ContractError { + Web3ContractError::Api(Web3ApiError::Decoder(format!( + "L1BatchCommitDataGeneratorMode::from_tokens: {tokens:?}" + ))) + } + match tokens.as_slice() { [ethabi::Token::Uint(enum_value)] => { if enum_value == &U256::zero() { @@ -74,10 +79,10 @@ impl Detokenize for L1BatchCommitDataGeneratorMode { } else if enum_value == &U256::one() { Ok(L1BatchCommitDataGeneratorMode::Validium) } else { - error + Err(error(&tokens)) } } - _ => error, + _ => Err(error(&tokens)), } } } diff --git a/core/lib/zksync_core/src/lib.rs b/core/lib/zksync_core/src/lib.rs index ba4eecfd161a..384372e1d551 100644 --- a/core/lib/zksync_core/src/lib.rs +++ b/core/lib/zksync_core/src/lib.rs @@ -310,7 +310,10 @@ async fn ensure_l1_batch_commit_data_generation_mode( // Getters contract support getPubdataPricingMode method Ok(l1_contract_pubdata_pricing_mode) => { let l1_contract_batch_commitment_mode = - L1BatchCommitDataGeneratorMode::from_tokens(l1_contract_pubdata_pricing_mode)?; + L1BatchCommitDataGeneratorMode::from_tokens(l1_contract_pubdata_pricing_mode) + .context( + "Unable to parse L1BatchCommitDataGeneratorMode received from L1 contract", + )?; // contracts mode == server mode anyhow::ensure!(

  • KZr5-Y%R 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 z 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